lvwerra HF Staff commited on
Commit
147b121
·
verified ·
1 Parent(s): 5b5da0e

Document storage bucket setup for template duplicates

Browse files
Files changed (4) hide show
  1. README.md +64 -16
  2. entrypoint.sh +1 -2
  3. setup.py +26 -8
  4. web/src/components/Locked.tsx +17 -2
README.md CHANGED
@@ -28,31 +28,79 @@ tmux-backed, so they survive disconnects. A **Skills** page distributes reusable
28
  ## Run your own (private) instance
29
 
30
  **Option A — one click:** press **⋮ → Duplicate this Space** at the top of this
31
- page. Keep visibility **Private**. That's it.
 
32
 
33
- **Option B — one command** (needs `pip install huggingface_hub` and `hf auth login`):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
 
35
  ```python
36
- from huggingface_hub import duplicate_space
37
- duplicate_space("lvwerra/agent-manager-template", private=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  ```
39
 
40
  Then open your new private Space and **log in to each agent inside its terminal**
41
- (run `claude`, `codex`, etc. and follow the prompt) credentials persist (see
42
- below). You can also set provider keys as Space **secrets** (`ANTHROPIC_API_KEY`,
43
- `OPENAI_API_KEY`, …) instead of logging in interactively.
44
 
45
- ## Persistence (optional no bucket required)
46
 
47
- The Space runs fine with **no storage at all**: it falls back to ephemeral disk,
48
- so you can try it immediately — but sessions, logins, and history reset whenever
49
- the Space sleeps or rebuilds.
 
 
50
 
51
- For durability, pick one (the app uses `/data` automatically either way):
52
 
53
- - **Persistent Storage** *(easiest)* — Space **Settings → Persistent Storage**,
54
- pick a tier. It mounts a real disk at `/data`. Done.
55
- - **Private bucket** — attach a private data source mounted at `/data`.
 
 
 
 
 
 
 
 
 
 
 
 
 
56
 
57
  Everything durable lives under `/data`: `sessions.json`, `groups.json`,
58
  `workspaces/<folder>/` (per-agent working dirs + shared `skills/`), and each
@@ -80,7 +128,7 @@ sessions are pinned to a stable per-session id so grouped agents don't collide).
80
  | Var | Default | Purpose |
81
  |---|---|---|
82
  | `PORT` | `7860` | HTTP + WS port (HF `app_port`) |
83
- | `DATA_DIR` | `/data` | Durable root (Persistent Storage or bucket mount) |
84
  | `USE_TMUX` | auto | `1`/`0` to force tmux on/off (off = direct PTY, no persistence) |
85
  | `ANTHROPIC_API_KEY` | — | Claude Code / opencode / Hermes (Space **secret**) |
86
  | `OPENAI_API_KEY` / `CODEX_API_KEY` | — | Codex (Space secret) |
 
28
  ## Run your own (private) instance
29
 
30
  **Option A — one click:** press **⋮ → Duplicate this Space** at the top of this
31
+ page. Keep visibility **Private**. Then create a private Storage Bucket and mount
32
+ it at `/data` before logging in:
33
 
34
+ ```python
35
+ from huggingface_hub import HfApi, Volume, create_bucket
36
+
37
+ api = HfApi()
38
+ space_id = "your-username/agent-manager"
39
+ bucket_id = "your-username/agent-manager-data"
40
+
41
+ create_bucket(bucket_id, private=True, exist_ok=True)
42
+ api.set_space_volumes(
43
+ space_id,
44
+ volumes=[
45
+ Volume(type="bucket", source=bucket_id, mount_path="/data"),
46
+ ],
47
+ )
48
+ api.restart_space(space_id)
49
+ ```
50
+
51
+ **Option B — one script** (needs `pip install -U huggingface_hub` and
52
+ `hf auth login`):
53
 
54
  ```python
55
+ from huggingface_hub import HfApi, Volume, create_bucket
56
+
57
+ api = HfApi()
58
+ space_id = "your-username/agent-manager"
59
+ bucket_id = "your-username/agent-manager-data"
60
+
61
+ create_bucket(bucket_id, private=True, exist_ok=True)
62
+ api.duplicate_repo(
63
+ from_id="lvwerra/agent-manager-template",
64
+ to_id=space_id,
65
+ repo_type="space",
66
+ private=True,
67
+ space_volumes=[
68
+ Volume(type="bucket", source=bucket_id, mount_path="/data"),
69
+ ],
70
+ )
71
  ```
72
 
73
  Then open your new private Space and **log in to each agent inside its terminal**
74
+ (run `claude`, `codex`, etc. and follow the prompt). You can also set provider
75
+ keys as Space **secrets** (`ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, …) instead of
76
+ logging in interactively.
77
 
78
+ ## Storage bucket (required for real use)
79
 
80
+ Agent Manager expects a private Storage Bucket mounted read-write at `/data`.
81
+ That bucket stores your sessions, workspaces, skills, CLI credentials, and
82
+ history. Without the bucket mount, the Space can still boot for preview, but it
83
+ falls back to ephemeral disk: sessions, logins, and history reset whenever the
84
+ Space sleeps or rebuilds.
85
 
86
+ If you duplicated first, you can add or replace the mount later:
87
 
88
+ ```python
89
+ from huggingface_hub import HfApi, Volume, create_bucket
90
+
91
+ api = HfApi()
92
+ space_id = "your-username/agent-manager"
93
+ bucket_id = "your-username/agent-manager-data"
94
+
95
+ create_bucket(bucket_id, private=True, exist_ok=True)
96
+ api.set_space_volumes(
97
+ space_id,
98
+ volumes=[
99
+ Volume(type="bucket", source=bucket_id, mount_path="/data"),
100
+ ],
101
+ )
102
+ api.restart_space(space_id)
103
+ ```
104
 
105
  Everything durable lives under `/data`: `sessions.json`, `groups.json`,
106
  `workspaces/<folder>/` (per-agent working dirs + shared `skills/`), and each
 
128
  | Var | Default | Purpose |
129
  |---|---|---|
130
  | `PORT` | `7860` | HTTP + WS port (HF `app_port`) |
131
+ | `DATA_DIR` | `/data` | Durable root (mounted private Storage Bucket) |
132
  | `USE_TMUX` | auto | `1`/`0` to force tmux on/off (off = direct PTY, no persistence) |
133
  | `ANTHROPIC_API_KEY` | — | Claude Code / opencode / Hermes (Space **secret**) |
134
  | `OPENAI_API_KEY` / `CODEX_API_KEY` | — | Codex (Space secret) |
entrypoint.sh CHANGED
@@ -4,8 +4,7 @@
4
  DATA_DIR="${DATA_DIR:-/data}"
5
  if ! mkdir -p "$DATA_DIR/workspaces" 2>/dev/null; then
6
  echo "WARN: $DATA_DIR is not writable — running EPHEMERAL (sessions/logins reset on restart)."
7
- echo " For durability, enable Persistent Storage in the Space settings (mounts at /data),"
8
- echo " or attach a private bucket at /data."
9
  DATA_DIR="$HOME/data"
10
  mkdir -p "$DATA_DIR/workspaces"
11
  fi
 
4
  DATA_DIR="${DATA_DIR:-/data}"
5
  if ! mkdir -p "$DATA_DIR/workspaces" 2>/dev/null; then
6
  echo "WARN: $DATA_DIR is not writable — running EPHEMERAL (sessions/logins reset on restart)."
7
+ echo " For durability, attach a private Storage Bucket mounted read-write at /data."
 
8
  DATA_DIR="$HOME/data"
9
  mkdir -p "$DATA_DIR/workspaces"
10
  fi
setup.py CHANGED
@@ -1,22 +1,40 @@
1
  #!/usr/bin/env python3
2
- """Spin up your own PRIVATE Agent Manager Space by duplicating the public template.
3
 
4
- pip install huggingface_hub
5
  hf auth login # or: huggingface-cli login
6
- python setup.py
7
 
8
- The new Space is private by default. Open it, then log in to each agent inside
9
- its terminal (run `claude`, `codex`, ...). Enable Persistent Storage in the
10
- Space settings if you want sessions/logins to survive restarts.
11
  """
12
  import sys
13
- from huggingface_hub import duplicate_space
14
 
15
  TEMPLATE = "lvwerra/agent-manager-template"
16
 
17
  if __name__ == "__main__":
18
  target = sys.argv[1] if len(sys.argv) > 1 else None # optional "you/your-space"
19
- res = duplicate_space(TEMPLATE, to_id=target, private=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  url = getattr(res, "url", res)
21
  print(f"\n✅ Created your private Space: {url}")
 
22
  print(" Keep it PRIVATE — this app has no authentication.")
 
1
  #!/usr/bin/env python3
2
+ """Spin up your own PRIVATE Agent Manager Space from the public template.
3
 
4
+ pip install -U huggingface_hub
5
  hf auth login # or: huggingface-cli login
6
+ python setup.py [your-username/agent-manager] [your-username/agent-manager-data]
7
 
8
+ The script creates a private Storage Bucket and mounts it read-write at /data
9
+ while duplicating the Space. Open the new private Space only after that, then
10
+ log in to each agent inside its terminal (run `claude`, `codex`, ...).
11
  """
12
  import sys
13
+ from huggingface_hub import HfApi, Volume, create_bucket
14
 
15
  TEMPLATE = "lvwerra/agent-manager-template"
16
 
17
  if __name__ == "__main__":
18
  target = sys.argv[1] if len(sys.argv) > 1 else None # optional "you/your-space"
19
+ api = HfApi()
20
+ if target and "/" in target:
21
+ namespace, space_name = target.split("/", 1)
22
+ else:
23
+ namespace = api.whoami()["name"]
24
+ space_name = target or TEMPLATE.rsplit("/", 1)[1]
25
+ bucket_id = sys.argv[2] if len(sys.argv) > 2 else f"{namespace}/{space_name}-data"
26
+
27
+ create_bucket(bucket_id, private=True, exist_ok=True)
28
+ res = api.duplicate_repo(
29
+ from_id=TEMPLATE,
30
+ to_id=target,
31
+ repo_type="space",
32
+ private=True,
33
+ space_volumes=[
34
+ Volume(type="bucket", source=bucket_id, mount_path="/data"),
35
+ ],
36
+ )
37
  url = getattr(res, "url", res)
38
  print(f"\n✅ Created your private Space: {url}")
39
+ print(f" Mounted private bucket at /data: {bucket_id}")
40
  print(" Keep it PRIVATE — this app has no authentication.")
web/src/components/Locked.tsx CHANGED
@@ -4,7 +4,22 @@ import { useState } from 'react';
4
  // disabled server-side; this explains how to run a private copy or relock.
5
  export default function Locked({ spaceId }: { spaceId?: string | null }) {
6
  const id = spaceId || 'owner/space-name';
7
- const cmd = `from huggingface_hub import duplicate_space\nduplicate_space("${id}", private=True)`;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
  const [copied, setCopied] = useState(false);
9
  const copy = () => {
10
  navigator.clipboard?.writeText(cmd).then(() => { setCopied(true); setTimeout(() => setCopied(false), 1500); }).catch(() => {});
@@ -22,7 +37,7 @@ export default function Locked({ spaceId }: { spaceId?: string | null }) {
22
 
23
  <h3>Run your own private copy</h3>
24
  <p className="locked-sub">
25
- Press <b>⋮ Duplicate this Space</b> above and keep it <b>Private</b>, or run:
26
  </p>
27
  <div className="locked-cmd">
28
  <pre><code>{cmd}</code></pre>
 
4
  // disabled server-side; this explains how to run a private copy or relock.
5
  export default function Locked({ spaceId }: { spaceId?: string | null }) {
6
  const id = spaceId || 'owner/space-name';
7
+ const cmd = `from huggingface_hub import HfApi, Volume, create_bucket
8
+
9
+ api = HfApi()
10
+ space_id = "your-username/agent-manager"
11
+ bucket_id = "your-username/agent-manager-data"
12
+
13
+ create_bucket(bucket_id, private=True, exist_ok=True)
14
+ api.duplicate_repo(
15
+ from_id="${id}",
16
+ to_id=space_id,
17
+ repo_type="space",
18
+ private=True,
19
+ space_volumes=[
20
+ Volume(type="bucket", source=bucket_id, mount_path="/data"),
21
+ ],
22
+ )`;
23
  const [copied, setCopied] = useState(false);
24
  const copy = () => {
25
  navigator.clipboard?.writeText(cmd).then(() => { setCopied(true); setTimeout(() => setCopied(false), 1500); }).catch(() => {});
 
37
 
38
  <h3>Run your own private copy</h3>
39
  <p className="locked-sub">
40
+ Create a private Storage Bucket mounted at <b>/data</b>, then duplicate this Space:
41
  </p>
42
  <div className="locked-cmd">
43
  <pre><code>{cmd}</code></pre>