Narrows what #305 allowed to the user's ruling: reordering, folding and tidying WIPs are out, and commit messages follow Conventional Commits with the ticket id at the end of the subject. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
6.4 KiB
Cloud Agents (LLM Reference)
Environment notes for agents running in Claude Code on the web. Local
checkouts are unaffected — the session hook exits early unless
CLAUDE_CODE_REMOTE=true.
.claude/hooks/session-start.sh handles the setup automatically. This doc
is the "why", and the record of what bites when it doesn't run.
The issue tracker is not issues.jsonl
.beads/issues.jsonl is a stale export. It is a viewer/interchange
artifact, not the source of truth — .beads/README.md says as much
("Cross-machine sync and backups use Dolt remotes/backups, not JSONL
import/export"). The real tracker is the Dolt database published to
refs/dolt/data on the git remote.
The gap is not cosmetic. A session that hydrated from the JSONL saw 121 issues against the remote's 168, with every P1 bug showing OPEN though all four were fixed and closed. Two beads were implemented from scratch that the remote had recorded as closed weeks earlier, and which turned out to be already implemented on an unmerged branch.
The hook syncs the database from the remote at session start. If it did not run, or reported a failure:
bd list --all | wc -l # 121 means you are on the stale export
Verify any bead against the code before starting it. git log --oneline --all | grep -oE 'improvise-[a-z0-9]{3}' names the ones already
referenced by a commit, and git log origin/main is worth a look for work
that landed without a bead reference.
bd init is destructive here
A bare bd init in this repo rewrites AGENTS.md, CLAUDE.md and
.claude/settings.json, installs Cursor/Codex integration files, and
commits all of it. It also rewrites sync.remote in
.beads/config.yaml.
Always pass the opt-outs:
bd init --non-interactive --skip-agents --skip-hooks -q --remote git+<origin>
Even then it commits a small .gitignore change, so the hook runs it in a
throwaway directory and copies only .beads/embeddeddolt back. Do the
same if you need to re-sync by hand; never run it in the working tree.
What does not work in this environment
| Thing | Status | Use instead |
|---|---|---|
nix develop unseeded |
Fails: flake inputs are GitHub tarballs, which are not served here | Run scripts/nix-seed-flake-inputs.sh first — see below. Or just use the preinstalled cargo/rustc, the same stable toolchain the flake pins |
bd dolt push |
Fails: 403 outbound | Nothing; bead status changes stay local. Say so rather than implying the tracker was updated |
git+ssh:// Dolt remote in config.yaml |
No ssh client in the container | git+https://<origin>, which the hook passes explicitly |
git push, GitHub API |
Work normally | — |
Nix itself installs and runs fine (no init system, so the daemon needs
starting by hand). Reads of public GitHub repos over the git protocol work —
it is specifically the /archive/*.tar.gz and codeload endpoints that are
refused.
Making nix develop work
scripts/nix-seed-flake-inputs.sh makes the devShell work without touching
flake.nix or flake.lock. Verified end to end: rustc 1.98.1, cargo,
crate2nix in the shell, git status clean.
Why it is needed, and why the obvious fixes are not available:
- Nix's
github:fetcher wants a tarball. GitHub traffic bypasses the environment's domain allowlist entirely and goes through a proxy that scopes API and release-asset requests to repositories attached to the session. A flake input from any other owner gets a 403. Raising network access to Full, or allowlistingcodeload.github.com, therefore does nothing. - Attaching the dependency repos is refused:
cross-tier adds are not supported in v1once the session already has sources from another owner. - Nix has no setting that makes
github:inputs use the git transport.
What does work is the lock's own integrity machinery. flake.lock records a
narHash per input, and Nix looks a source up in the store and its
substituters before fetching. The git and tarball fetchers produce
byte-identical trees for a revision, so a git+https prefetch at the locked
rev lands the input at exactly the store path the lock names:
lock narHash: sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=
git prefetch: sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=
The script does that for every locked input. Nix still verifies each tree
against the recorded hash, so this satisfies the lock rather than working
around it — a mismatch fails loudly. Do not instead rewrite the lock's nodes
to git type: carrying the old narHash onto a different fetcher is exactly
the claim the lock exists to make.
It is not in the session-start hook because it is expensive (minutes, plus several GB of store once the devShell builds) and most work does not need the devShell. Run it when you do.
Two alternatives if per-container seeding is unattractive: push the inputs to
a binary cache with nix flake archive and point sessions at it with
NIX_CONFIG/extra-substituters plus a Custom allowlist entry for the
cache host (not GitHub, so the allowlist does apply); or use a self-hosted
environment, where egress leaves through your own network boundary.
cache.nixos.org is reachable, so the build itself substitutes normally.
Sharp edges in bd
bd dolt push <remote>ignores its argument and pushes toorigin. Pointing it at a throwaway remote does not keep the real one out of it; only the 403 does. Treat the named form as unsafe.bd dolt pullinto a divergent local database fails withlocal changes would be stomped by merge. Re-sync from the remote instead of merging.bdwarns if.beadsis not mode 0700.
Working conventions
- One bead per pull request. Stacking a second bead onto an open PR has been rejected in review.
- A merged PR cannot carry follow-up work: restart from the latest default branch and open a new PR.
- Reconcile diverging history only by merge, including when bringing the
default branch into a working branch. Never rebase onto main, and never do
anything that needs a force push. Add a new Conventional Commit by default.
Only an unpushed HEAD may be amended, and only for a small fix. Never
reorder or fold commits (
.agents/skills/wave/agent-rules.md, rule 8). - Keep
context/repo-map.mdandcontext/design-principles.mdcurrent — they are the two docs agents are expected to maintain by hand.