polats Claude Opus 5 (1M context) commited on
Commit
e1f9a64
·
1 Parent(s): 1933995

Let the agent manage Hugging Face repos when HF_TOKEN is set

Browse files

Installs the official hf CLI (in a venv, since Debian's Python is
externally-managed) and, at boot, drops agents/hf-spaces.md in as opencode's
global AGENTS.md — the config-dir path applies to every session regardless of
which directory is open, so the guidance does not depend on a workspace file
that an ephemeral container would lose. With no HF_TOKEN present the file is
removed instead, so the instructions never advertise access the container
does not have.

The doc leads with "never print the token" because session transcripts are
shareable, and it draws the line at creating repos: deleting, renaming or
changing visibility needs the user's confirmation first. Image grows ~134MB
for python3 plus the CLI.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

Files changed (4) hide show
  1. Dockerfile +14 -0
  2. README.md +23 -0
  3. agents/hf-spaces.md +83 -0
  4. entrypoint.sh +20 -0
Dockerfile CHANGED
@@ -12,11 +12,24 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
12
  jq \
13
  less \
14
  openssh-client \
 
 
15
  ripgrep \
16
  tar \
17
  unzip \
18
  && rm -rf /var/lib/apt/lists/*
19
 
 
 
 
 
 
 
 
 
 
 
 
20
  # Install opencode at BUILD time so cold starts don't re-download the release.
21
  # The official installer hardcodes $HOME/.opencode/bin (it ignores
22
  # OPENCODE_INSTALL_DIR), so move the binary onto the shared PATH afterwards.
@@ -34,6 +47,7 @@ ENV HOME=/home/node
34
  ENV PATH=/usr/local/bin:${PATH}
35
 
36
  COPY --chown=node:node entrypoint.sh /home/node/entrypoint.sh
 
37
  RUN chmod +x /home/node/entrypoint.sh \
38
  && mkdir -p /home/node/workspace \
39
  && chown -R node:node /home/node
 
12
  jq \
13
  less \
14
  openssh-client \
15
+ python3 \
16
+ python3-venv \
17
  ripgrep \
18
  tar \
19
  unzip \
20
  && rm -rf /var/lib/apt/lists/*
21
 
22
+ # Official Hugging Face CLI, so an agent holding HF_TOKEN can create and push
23
+ # repos in one step instead of hand-rolling API calls. Debian marks its Python
24
+ # externally-managed (PEP 668), hence the venv rather than a bare pip install.
25
+ RUN python3 -m venv /opt/hf-cli \
26
+ && /opt/hf-cli/bin/pip install --no-cache-dir --upgrade pip \
27
+ && /opt/hf-cli/bin/pip install --no-cache-dir "huggingface_hub[cli]" \
28
+ && for bin in hf huggingface-cli; do \
29
+ [ -x "/opt/hf-cli/bin/$bin" ] && ln -sf "/opt/hf-cli/bin/$bin" "/usr/local/bin/$bin"; \
30
+ done \
31
+ && hf version
32
+
33
  # Install opencode at BUILD time so cold starts don't re-download the release.
34
  # The official installer hardcodes $HOME/.opencode/bin (it ignores
35
  # OPENCODE_INSTALL_DIR), so move the binary onto the shared PATH afterwards.
 
47
  ENV PATH=/usr/local/bin:${PATH}
48
 
49
  COPY --chown=node:node entrypoint.sh /home/node/entrypoint.sh
50
+ COPY --chown=node:node agents/hf-spaces.md /home/node/agents/hf-spaces.md
51
  RUN chmod +x /home/node/entrypoint.sh \
52
  && mkdir -p /home/node/workspace \
53
  && chown -R node:node /home/node
README.md CHANGED
@@ -104,6 +104,28 @@ your own domain needs `OPENCODE_CORS_ORIGINS=https://your.domain`.
104
 
105
  ---
106
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
107
  ## Read this before you deploy
108
 
109
  - **This is a remote shell.** Every route allows command execution and file
@@ -131,6 +153,7 @@ your own domain needs `OPENCODE_CORS_ORIGINS=https://your.domain`.
131
  | `OPENCODE_STATE_ROOT` | `/data` | Where to look for a writable volume. |
132
  | `OPENCODE_WORKSPACE` | `$STATE_ROOT/workspace` or `$HOME/workspace` | Directory to serve. |
133
  | `OPENCODE_CORS_ORIGINS` | — | Comma-separated extra CORS origins. |
 
134
 
135
  Build arg `OPENCODE_VERSION` pins a release (default: latest).
136
 
 
104
 
105
  ---
106
 
107
+ ## Giving the agent Hugging Face access
108
+
109
+ Set `HF_TOKEN` as a Space secret (or Railway variable) and the agent can create
110
+ and manage Hugging Face repos: the official `hf` CLI is installed in the image,
111
+ it picks the token up from the environment with no login step, and `entrypoint.sh`
112
+ installs [`agents/hf-spaces.md`](agents/hf-spaces.md) as opencode's global
113
+ `AGENTS.md` so the agent knows the recipes. With no `HF_TOKEN` set, that file is
114
+ removed and nothing advertises the capability.
115
+
116
+ > **This hands your HF account to whoever can reach the server.** A standard HF
117
+ > write token covers every repo the account can write to — including org repos —
118
+ > so the blast radius is much larger than "a shell in a container". Two things
119
+ > make it meaningfully safer:
120
+ >
121
+ > - Use a **fine-grained token** scoped to just the permissions you need (write
122
+ > access to Spaces, say) rather than an account-wide write token.
123
+ > - Remember the agent reads untrusted content — repos, web pages, issue text.
124
+ > Anything it reads can try to talk it into using the token. The instructions
125
+ > tell it never to print the token, but that is a speed bump, not a boundary.
126
+
127
+ ---
128
+
129
  ## Read this before you deploy
130
 
131
  - **This is a remote shell.** Every route allows command execution and file
 
153
  | `OPENCODE_STATE_ROOT` | `/data` | Where to look for a writable volume. |
154
  | `OPENCODE_WORKSPACE` | `$STATE_ROOT/workspace` or `$HOME/workspace` | Directory to serve. |
155
  | `OPENCODE_CORS_ORIGINS` | — | Comma-separated extra CORS origins. |
156
+ | `HF_TOKEN` | — | Optional. A Hugging Face token, which lets the agent create and manage HF repos with the bundled `hf` CLI. See the warning below. |
157
 
158
  Build arg `OPENCODE_VERSION` pins a release (default: latest).
159
 
agents/hf-spaces.md ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Hugging Face access
2
+
3
+ `HF_TOKEN` is present in this container's environment and the official `hf` CLI
4
+ is installed, so you can create and manage Hugging Face repos directly.
5
+
6
+ **Never print, echo, cat or otherwise reveal the value of `HF_TOKEN`.** Pass it
7
+ by variable reference only. Session transcripts can be shared, and this token
8
+ carries write access to the whole account.
9
+
10
+ ## Who am I
11
+
12
+ ```bash
13
+ hf auth whoami
14
+ ```
15
+
16
+ The CLI reads `HF_TOKEN` from the environment; there is no login step.
17
+
18
+ ## Create a Space
19
+
20
+ ```bash
21
+ hf repo create my-space --repo-type space --space_sdk docker
22
+ ```
23
+
24
+ Then populate it. A Docker Space needs, at minimum, a `README.md` whose YAML
25
+ front matter declares the SDK and the port your app listens on, plus a
26
+ `Dockerfile`:
27
+
28
+ ```markdown
29
+ ---
30
+ title: My Space
31
+ emoji: 🚀
32
+ colorFrom: gray
33
+ colorTo: indigo
34
+ sdk: docker
35
+ app_port: 7860
36
+ ---
37
+ ```
38
+
39
+ `app_port` must match what the container actually listens on. Hugging Face
40
+ exposes exactly one port and routes it through HTTPS on 443 — a Space cannot
41
+ serve a second port, and clients must not append a port to the `*.hf.space`
42
+ URL.
43
+
44
+ Upload files with the CLI:
45
+
46
+ ```bash
47
+ hf upload <user>/<space> ./local-dir . --repo-type space
48
+ ```
49
+
50
+ …or use git, keeping the token out of the stored remote:
51
+
52
+ ```bash
53
+ git clone "https://huggingface.co/spaces/<user>/<space>" && cd <space>
54
+ # commit files, then:
55
+ git push "https://$(hf auth whoami | head -1):${HF_TOKEN}@huggingface.co/spaces/<user>/<space>" HEAD:main
56
+ ```
57
+
58
+ ## Set Space secrets
59
+
60
+ Secrets are the only correct place for credentials — never commit them.
61
+
62
+ ```bash
63
+ curl -sf -X POST "https://huggingface.co/api/spaces/<user>/<space>/secrets" \
64
+ -H "Authorization: Bearer $HF_TOKEN" -H "Content-Type: application/json" \
65
+ -d '{"key":"SOME_KEY","value":"...","description":"what it is for"}'
66
+ ```
67
+
68
+ ## Check whether a Space is up
69
+
70
+ ```bash
71
+ curl -s "https://huggingface.co/api/spaces/<user>/<space>" | jq '.runtime.stage'
72
+ ```
73
+
74
+ `RUNNING` is healthy. `BUILD_ERROR` / `RUNTIME_ERROR` / `CONFIG_ERROR` mean it
75
+ failed — read the build logs on the Space page. Free `cpu-basic` Spaces are
76
+ ephemeral and are stopped after roughly 48h idle, so anything that must survive
77
+ belongs in git or on a persistent-storage mount at `/data`.
78
+
79
+ ## Ask before destroying things
80
+
81
+ Creating repos is fine. Deleting or renaming an existing repo, changing its
82
+ visibility, or overwriting someone else's files is not reversible — confirm with
83
+ the user first.
entrypoint.sh CHANGED
@@ -61,6 +61,26 @@ cd "$WORKSPACE"
61
  # which makes git refuse to touch the repo. Trust what we already control.
62
  git config --global --add safe.directory '*' 2>/dev/null || true
63
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
  # --- extra CORS origins ----------------------------------------------------
65
  # localhost, *.opencode.ai and the desktop app's oc://renderer are allowed out
66
  # of the box (packages/server/src/cors.ts). Only a frontend you host yourself
 
61
  # which makes git refuse to touch the repo. Trust what we already control.
62
  git config --global --add safe.directory '*' 2>/dev/null || true
63
 
64
+ # --- agent instructions ----------------------------------------------------
65
+ # opencode reads a global AGENTS.md from its config dir (global.config/AGENTS.md),
66
+ # which applies to every session regardless of which directory is open. Install
67
+ # the Hugging Face guidance there when a token is actually present, so the
68
+ # instructions never advertise a capability the container does not have.
69
+ CONFIG_DIR="${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}"
70
+ if [ -n "${HF_TOKEN:-}" ] && [ -f "$HOME/agents/hf-spaces.md" ]; then
71
+ mkdir -p "$CONFIG_DIR"
72
+ {
73
+ echo "<!-- Generated by entrypoint.sh on boot. Edit agents/hf-spaces.md in the"
74
+ echo " opencode-cloud repo instead; changes here are overwritten. -->"
75
+ echo
76
+ cat "$HOME/agents/hf-spaces.md"
77
+ } > "$CONFIG_DIR/AGENTS.md"
78
+ echo "hugging face: HF_TOKEN present, \`hf\` CLI available, agent instructions installed"
79
+ else
80
+ rm -f "$CONFIG_DIR/AGENTS.md" 2>/dev/null || true
81
+ echo "hugging face: no HF_TOKEN set — agent has no Hugging Face access"
82
+ fi
83
+
84
  # --- extra CORS origins ----------------------------------------------------
85
  # localhost, *.opencode.ai and the desktop app's oc://renderer are allowed out
86
  # of the box (packages/server/src/cors.ts). Only a frontend you host yourself