This is the canonical repo-level agent guide for Clawdapus. CLAUDE.md should be a symlink to this file.
Clawdapus is infrastructure-layer governance for AI agent containers. The claw CLI is a Go binary that treats agents as untrusted workloads: reproducible, inspectable, diffable, and killable.
Core docs:
MANIFESTO.md— project visionREADME.md— current user-facing CLI and examplesdocs/CLLAMA_SPEC.md— cllama proxy contractdocs/decisions/— ADRsdocs/plans/— implementation plans and historical design notes- GitHub Project Board — prioritized roadmap (kanban).
Workflow:
- move an issue to
In progresswhen actively working on it - use
Readyonly for work that is queued up but not yet being worked - move an issue to
In reviewwhen implementation, docs, and verification are complete - move an issue to
Doneonly after review/acceptance, not immediately after coding
- move an issue to
All planned work is tracked as GitHub issues and prioritized on the project board. This applies to agents and human collaborators alike.
Before starting any non-trivial task:
- Find the relevant issue on the project board. If none exists, create one first — do not start work without an issue.
- The issue must contain enough context for any model (or human) to resume cold: motivation, constraints, key design decisions, and open questions. A future collaborator with no prior context should be able to pick it up from the issue alone.
- Move the issue to In Progress before beginning.
- Do the work on a branch or worktree tied to that issue.
- Move the issue to Done (or close it) when the work lands on master.
Planning goes into issues. Design notes, constraints, open questions, and sub-tasks belong in the issue body or comments — not in local plan files, unless the plan is large enough to warrant a docs/plans/ document (linked from the issue).
The project board is the single source of truth for priorities. Column order within a status column reflects relative priority. Work the top item unless there is a blocking reason not to.
Closing keywords in PR bodies are required. The board has automation enabled for Item closed, Pull request merged, and Auto-close issue. These workflows only fire when GitHub can link a PR to its issue, which requires a closing keyword in the PR body:
Closes #137
Fixes #137, #146
Resolves #137
Branch names like issue-137-* are a human convention — GitHub does not infer the linkage from them. If the PR body omits a closing keyword, the issue stays Open and the card stays in Ready after merge, requiring manual cleanup. Always include Closes #<n> (one per covered issue) when opening a PR.
Releases are tag-driven and cut by the maintainer using the clawdapus-release skill, not by feature PRs. Agents working on a fix or feature must keep release artifacts out of their PR. Touching them looks harmless but breaks the release pipeline because they ride a coordinated lockstep across image builds, the cllama submodule, GitHub releases, and the published site.
Do not in a feature PR:
- Bump pins in
internal/infraimages/release_manifest.go(DefaultClawInfraTag,DefaultCllamaTag,DefaultHermesBaseTag). These constants must move together with a real release. If you change them in a feature PR, the next clawdapus release verifier (scripts/check-release-infra-tags) will fail because the corresponding:vX.Y.Zimages do not exist yet, or — worse — the release will tag and ship with pins pointing at images that contain code different from the source tree at the tag commit. - Add a new version section in
site/changelog.mdwith the<Badge type="tip" text="Latest" />. That badge moves only when a real GitHub release exists for that tag. Site deploy fires on every push to master, so adding the badge in a feature PR makesclawdapus.dev/changelogclaim a release exists when it doesn't. Use the## Unreleasedsection instead. - Bump the nav dropdown version in
site/.vitepress/config.mts. Same reason: site deploys immediately on master push, so the dropdown becomes a public lie. - Move the
cllamasubmodule pointer past the most recent cllama tag. If your fix needs new cllama code, cut a cllama release first (v0.X.Ytag in the submodule + GitHub release + multi-arch image push to ghcr.io), then bump the submodule pointer to the released commit. A submodule pointer past the latest cllama tag means the next clawdapus release will pincllama:vX.Y.Z(a real image) but the source tree references commits that did not ship in that image — i.e. the runtime fix you wrote is invisible to users. - Build or push
hermes-baseor any infra image without coordinating with the maintainer. There is no auto-publish workflow forhermes-base; bumpingDefaultHermesBaseTagrequires a manualdocker buildx build --pushfromdockerfiles/hermes-base/. If the constant points at an unpublished tag, the release verifier fails. - Anonymize or rewrite identifying details in historical changelog entries (e.g. "Tiverton" → "downstream"). Old entries are part of the project's incident record. Edit only the entry you are adding; leave history alone unless the maintainer explicitly asks for a rewrite.
Be aware of what merging to master actually does:
- The image workflows (
claw-api-image.yml,clawdash-image.yml,claw-wall-image.yml,claw-mcp-stdio-image.yml) trigger on every master push and publish:latestand:<sha>image tags. They do not publish:vX.Y.Z— that only happens when the maintainer pushes av*git tag, which is the release boundary. deploy-site.ymltriggers on every master push touchingsite/**. Whatever the changelog and nav say at the time of merge is whatclawdapus.devwill show. There is no "release-only" gate on the site.
If a release-related artifact genuinely needs to change in a fix PR, leave a note in the PR body explaining what the maintainer must do to ship the fix (e.g. "Submodule pointer moves past v0.5.0; cllama v0.5.1 release required before next clawdapus release"). Do not silently bake the requirement into the diff — a future agent reading the PR cannot tell that an out-of-band step is missing.
Do not reference specific deployments or their agents by name in public Clawdapus or cllama artifacts — changelog entries, release notes, issue comments, generated docs, PR bodies. Clawdapus is a general tool; named downstream deployments (Tiverton, the trading desk pod, individual claws like Boulton/Logan/Westin/etc.) are use cases. Describe symptoms and fixes generically: "Hermes runners", "Anthropic-format runners", "Discord-channel-consuming agents", "production deployments", "downstream operators". Internal investigation channels (talking-stick rooms, private repos, agent memory) are where deployment-specific context lives. The public OSS surface stays general. This applies to both new changelog entries and existing ones — leave historical entries alone unless the maintainer explicitly asks for a rewrite, but never add a new entry that names a downstream deployment.
claw up is a compiler. These principles govern the pipeline and must not be violated by new features:
- Compile-time, not runtime. All wiring — feeds, skills, identity, surfaces — is resolved during
claw up. No runtime self-registration. The generated compose file is the single source of truth. - Provider-owns, consumer-subscribes. Services declare what they offer (feeds, endpoints, auth). Agents subscribe by name. Consumers never need to know a service's URL path or TTL.
- Pod-level defaults, service-level overrides. Shared config is declared once at pod level. Services inherit by default, override or extend (
...spread) as needed. - One canonical descriptor. A service's capabilities are declared once (via
claw.describein the image) and projected into whatever artifacts need them. No manual duplication across pod YAML, skills, and CLAWDAPUS.md. - Services self-describe. Images carry structured descriptors.
claw upextracts and compiles them. Framework adapters (RailsTrail, etc.) generate descriptors from code introspection.
See ADR-017 for the full design and docs/plans/2026-03-22-pod-defaults-and-service-self-description.md for implementation details.
There is some doc drift in the repo. When sources disagree, trust them in this order:
- Current code in
cmd/claw/andinternal/ - Current tests
- Examples under
examples/ - ADRs in
docs/decisions/ - Plans/reviews in
docs/plans/anddocs/reviews/
Example: TESTING.md still talks about e2e, but the build tags currently in-tree are integration and spike.
Current top-level commands are:
claw pullclaw buildclaw upclaw downclaw psclaw logsclaw healthclaw inspectclaw doctorclaw initclaw api(schedulesubcommands)claw agent addclaw compose(use this liberally instead of invoking docker directly)
Useful current behavior:
claw upwritescompose.generated.ymlnext to the pod file.- If the pod contains managed
x-clawservices,claw upcurrently requires detached mode: useclaw up -d. docker composeis the sole lifecycle writer. Docker SDK usage is read-only.
If you are debugging or changing behavior, these are the main entry points:
cmd/claw/compose_up.go— main runtime orchestration pathinternal/pod/—claw-pod.ymlparsing and compose emissioninternal/clawfile/— Clawfile parsing and Dockerfile emissioninternal/driver/— driver registry and per-runner implementationsinternal/cllama/— cllama context generation and wiring helpersinternal/inspect/— claw label parsing from imagesinternal/describe/—claw.describeservice descriptor extraction, parsing, and feed registryinternal/persona/— persona materializationcllama/— proxy implementation source
The best end-to-end fixtures are:
examples/quickstart/examples/trading-desk/examples/rollcall/(this must remain a full spike test)
Driver directories currently in-tree:
internal/driver/openclawinternal/driver/hermesinternal/driver/nanobotinternal/driver/nanoclawinternal/driver/picoclawinternal/driver/microclawinternal/driver/nullclawinternal/driver/shared
Do not assume older docs mentioning only a subset are current.
- A
Clawfileis parsed and emitted into a standard Dockerfile using image labels for Clawdapus directives. - A
claw-pod.ymlis parsed from service-levelx-clawblocks. Current parsed fields includeagent,persona,describe-file,cllama,cllama-env,models,count,handles,feeds,tools,tool-policy,memory,include,surfaces,skills,invoke,claw-api, andmcp-stdio. Pod-levelx-clawalso acceptssequential-conformance: true. count > 1expands into ordinal-named compose services likesvc-0,svc-1, etc.x-claw.masteris fully wired: parsed (internal/pod/parser.go), validated against declared services at parse time, and consumed incmd/claw/compose_up.go, where it drivesclaw-apiauto-injection (see the master-claw bullet under Practical Guidance).- cllama wiring is resolved before materialization in a two-pass
claw upflow. - Generated runtime artifacts like
AGENTS.generated.md,CLAWDAPUS.md, cllama context files, and runner configs are produced under runtime dirs duringclaw up. - cllama context layout: host-side at
.claw-runtime/context/<agent-id>/containingAGENTS.md,CLAWDAPUS.md,metadata.json. Mounted into cllama container at/claw/context/<agent-id>/. Thecontext/directory segment is required.
- Bug fixes in one driver often apply to all 7. When fixing driver behavior (permissions, config defaults, env vars), check all drivers in
internal/driver/*/driver.goandconfig.go— not just the one mentioned in the issue. - Runtime directories created by
Materialize()use0o777(not0o700) so container users with different uids can write. Do not regress this. - All drivers set
mention_only(or equivalent likerequireMention,DISCORD_REQUIRE_MENTION) for Discord channels. Without this, multi-agent pods enter feedback loops. - All drivers explicitly set
HOMEin the container env map to match their config mount path. Container base images may run as root or a different user than expected. cllama/is a git submodule pointing to a public SSH repo. Freshgit cloneleaves it empty. Infra images (cllama, clawdash) are published to ghcr.io as public packages to avoid this for end users.cllama/has its own.git— changes require two commits: one insidecllama/(for feeds/proxy code), thengit add cllama && git commitin the repo root to update the pointer. Shell working directory can silently drift tocllama/between commands — use absolute paths for git operations or verify withpwdfirst.internal/feeds/and other cllama internals live atcllama/internal/, not at the repo root.- Infra image remediation is explicit now:
claw pullowns pinned infra freshness and built-in local runner alias freshness (openclaw:latest,nanobot:latest,nanoclaw-orchestrator:latest, etc.) refreshed viadocker build --pull --no-cache;claw buildowns podbuild:services and consumes an already-refreshed runner alias;claw uppoints at one or the other when something is missing.claw up --fixis the opt-in auto-remediation path. Useclaw pull --no-runnersfor the fast pinned-infra-only path. See ADR-024. - Runner base provenance:
claw buildrewritesFROM <alias>:latesttoFROM <alias>:v<version>inDockerfile.generatedand stamps three labels (claw.runner.built-against,claw.runner.image-id,claw.runner.recipe-sha).claw upreadsclaw.runner.image-idand prints a soft drift hint when the local alias has moved on; it does not auto-rebuild. Service images built with a manualdocker buildof a runner base must also create a versioned sibling tag, otherwiseclaw buildwill fail-closed with aclaw pullremediation hint. - Managed services require
claw up -dbecause post-apply verification is fail-closed. - Multi-proxy cllama is represented in the data model but runtime currently fails fast if more than one proxy type is declared.
- cllama proxy handler (
cllama/internal/proxy/handler.go) is pure passthrough: it rewrites themodelfield and forwards. It does NOT touch themessagesarray. No prompt decoration, no system message injection, no middleware hooks exist. Two distinct code paths handle OpenAI format (messages[]) vs Anthropic format (top-levelsystemfield). - cllama providers.json: v1 format uses top-level
api_key; v2 usesversion: 2+keys[]array withstate/secret/id. Old cllama images (pre-v0.2.2) silently load v2 files with empty key pools → every request returns "missing API key for {provider}" 502. Refresh through the four-verb flow:claw pull, thenclaw up -d(orclaw up --fix -d) so Docker recreates the proxy container from the pulled image. - cllama SSE endpoint for debugging provider key state:
curl -N -H "Authorization: Bearer <ui_token>" http://<host>:<port>/events— the initialdata:payload hasproviders[name].maskedKey; empty string means no active key loaded. - Hermes gateway log (inside container):
/root/.hermes/logs/gateway.log— shows all received Discord events. Zero entries after startup means the bot is connected but not receiving messages (stale gateway session or missingMESSAGE_CONTENTintent). - cllama context mount (
agentctx) currently holds onlyAgentsMD,ClawdapusMD, andMetadata(for bearer token auth). No outbound service credentials, no feed manifests, no decoration config. - cllama session history:
claw upbind-mounts.claw-session-history/→/claw/session-historyin the cllama container when cllama is enabled. cllama writes<dir>/<agent-id>/history.jsonl— one entry per successful 2xx completion. This is infrastructure-owned (proxy-written). Agents have no read API against it in Phase 1. Distinct from/claw/memory, which is runner-owned. Both surfaces are persistent across container restarts AND driver migrations (CLAW_TYPEchanges). - Claw-authored skills:
claw upbind-mounts.claw-skills/<claw-id>/skills/→ the driver-reportedSkillDir(rw), with pod-declaredSKILLfiles layered read-only on top. The host dir is keyed by compose service name, so forcount > 1each ordinal gets its own dir (.claw-skills/worker-0/skills/,worker-1/...). This is an asymmetry with.claw-memory/<base-svc>/memory/, which is shared across ordinals — skills are identity-coupled, memory is currently service-coupled. Per-ordinal memory isolation is a separate issue. Mount selection for ordinal services usesdriver.Mount.HostPathByService; the baseHostPathis left empty in that case. - Provider API keys for cllama-managed services belong in
x-claw.cllama-env, not regular agentenvironment:blocks. Native Gemini usesGEMINI_API_KEYas the primary env name and also acceptsGOOGLE_API_KEYas a lower-priority alias. - For cllama-enabled
count > 1services, bearer tokens and context are per ordinal, not per base service. compose.generated.ymlandDockerfile.generatedare generated artifacts. Inspect them, but do not hand-edit them as source.- OpenClaw config and cron paths are mounted as directories, not single files, because the runtime performs atomic rewrites.
- OpenClaw
openclaw health --jsoncan emit noise to stderr. The repo handles it as a stdout-first parse path. - cllama logger (
cllama/internal/logging/logger.go): fieldintervention *stringhas noomitempty— every event emits"intervention": null. Emittedtypevalues arerequest,response,error,intervention. Nodrift_scoreexists in the reference implementation. The spec (CLLAMA_SPEC.md§5) omitserrorfrom its type enum and usesintervention_reasonwhere the logger usesintervention. - Hermes SOUL.md identity: The Hermes runner seeds a default SOUL.md ("You are Hermes, made by Nous Research") on first boot via
hermes_cli/default_soul.py. The Clawdapus Hermes driver writes its ownSOUL.mdtohermes-home/duringMaterializeto override this with the agent's contracted identity. Persona SOUL.md takes priority when configured. - Hermes
.envpassthrough: Container env vars from composeenvironment:are NOT available in Hermes agent tool execution. Only vars inallowedEnvPassthroughKeys()(internal/driver/hermes/config.go) reach the tool runtime via the.envfile. New env vars that agents need (e.g.CLAW_API_TOKEN) must be added to this list. - Pod-level
x-clawacceptspod,master,handles-defaults,cllama-defaults,models-defaults,surfaces-defaults,feeds-defaults,tools-defaults,tool-policy-defaults,memory-defaults,skills-defaults, andprincipals.tool-policy/tool-policy-defaultsoverride cllama's managed-tool mediation budgets (max-rounds,timeout-per-tool-ms,total-timeout-ms); omitted fields keep the compiled-in defaults. Service-level fields inherit pod defaults; declaring a field replaces defaults unless...spread is used to extend.x-claw.modelsmerges additively overmodels-defaults, then the merged pod slots overlay imageMODELlabels at compile time.models: {}andmodels: nullsuppress pod defaults only; they do not remove image-declared slots. Seeexamples/master-claw/claw-pod.ymlfor the general defaults pattern. claw-api: selfon a service'sx-clawblock is an authority signal — it auto-generates a read-only bearer token scoped to that service and injectsCLAW_API_URL+CLAW_API_TOKEN. This is separate fromsurfaces: [service://claw-api]which only grants network reachability. Both are needed for full access.- claw-api principal scopes have four dimensions:
pods,services(base service names),claw_ids(ordinal IDs),compose_services(compose service names, used for write-plane ordinal targeting). All five write verbs are implemented incmd/claw-api/handler.go:fleet.restart,fleet.quarantine,fleet.budget.set,fleet.model.restrict, andschedule.control. sequential-conformance: trueat pod level allows services to share the same Discord handle ID (rollcall pattern). Without it, duplicate handle IDs across services are a hard error. Thecount > 1rejection is still enforced even in sequential-conformance pods.claw-wallis an infrastructure service auto-injected byclaw upwhen any cllama-enabled service has Discord channel IDs. The service nameclaw-wallis reserved — declaring it inclaw-pod.ymlis a hard error. Credentials are passed asCLAW_WALL_TOKENS=channelID:token,...pairs (not a map), with exactly one reader token selected per consumed channel. The message store and cursors are in-memory, but wall backfills Discord history on startup before the first forward poll up toCLAW_WALL_RETENTION(default24h) andCLAW_WALL_BACKFILL_MAX_PAGES(default25). Feed headers includebackfill_status;partialorrate_limitedmeans actual 24h coverage was not guaranteed.- Verb validation is split: unknown verbs in
x-claw.principalsfail hard at pod parse time, while unknown verbs inprincipals.jsonare dropped with warnings; a principal left with no recognized verbs still loads but authorizes nothing. claw.describeis the structured service descriptor label.claw upextracts.claw-describe.jsonfrom images (or falls back to the build context filesystem). Descriptors declare feeds, endpoints, auth, and skill file paths. Feed names from descriptors populate a pod-global feed registry; consumers subscribe by name via short-formfeeds: [name].- Feed resolution is two-phase: the parser stores short-form feed names as
FeedEntry{Unresolved: true}(no source/path validation).claw upresolves them after image inspection against the feed registry. Unresolved feeds that aren't in the registry are hard errors. - Spread expansion (
...) in pod default lists happens at the raw YAML layer inexpandPodDefaults(), BEFORE typed parsing (ParseSurface,parseFeeds). The typed parsers never see the...token. This ordering is critical — moving spread expansion after typed parsing will break.
- Lifecycle commands (
ps,logs,health,compose) refuse to run ifclaw-pod.ymlis newer thancompose.generated.yml.claw downis exempt — you can always tear down a stale pod. Runclaw upto regenerate. claw compose <subcommand> [args...]passes through todocker compose -f compose.generated.yml. Use it for any compose operation not covered by the named shortcuts (e.g.claw compose exec analyst bash,claw compose restart cllama-passthrough).HANDLEand channelSURFACEare different layers in current code.HANDLEis identity/bootstrap data; channelSURFACEis routing policy. If both are present, surface-level routing config is applied after handle defaults.- Map-form channel surfaces are still real code paths at the pod layer;
ClawBlock.Surfacesis parsed into[]driver.ResolvedSurface, not raw strings. - CLAWDAPUS.md is the single generated context document per agent. Surface metadata (service endpoints, channel config, handles) is inlined into CLAWDAPUS.md sections. Separate
surface-*.mdandhandle-*.mdskill files are no longer generated. Large service skill files (fromclaw.describeorclaw.skill.emit) are still mounted separately at/claw/skills/with a pointer in CLAWDAPUS.md. - OpenClaw cllama wiring does not write to
agents.defaults.model.baseURL/apiKey; the schema-valid rewrite path ismodels.providers.<provider>.{baseUrl,apiKey,api,models}. PERSONAis implemented as runtime materialization. Local refs are copied with traversal/symlink hardening; non-local refs are pulled as OCI artifacts.CLAW_PERSONA_DIRis only set when a persona is present.x-claw.includecontract composition is live.enforceandguidecontent is inlined into generatedAGENTS.md;referencecontent is mounted as read-only skill material.- The
Driverinterface (internal/driver/types.go) has four methods:Validate,Materialize,PostApply,HealthProbe. All run once at deploy/startup. There is no per-turn or per-request hook — any per-request context enrichment must go through cllama or a runner-native mechanism.
Current test layers:
- Unit:
go test ./... - Vet:
go vet ./... - Integration-tagged tests:
go test -tags integration ./... - Live/Docker spike tests:
go test -tags spike -run TestSpikeRollCall ./cmd/claw/...orgo test -tags spike -run TestSpikeComposeUp ./cmd/claw/...
Build tags currently present in the repo:
integrationspike
The spike tests are the heavy end-to-end path. They build images, run Docker, and in some cases require real Discord/provider credentials.
TestSpikeRollCallis the primary validation for cllama proxy enforcement. Every claw in the rollcall pod must make at least one real LLM call through cllama, andclaw auditmust show telemetry for all of them. If you change cllama wiring, driver materialization, feed injection, or telemetry normalization, this spike test is how you prove it works end-to-end.docs_quickstart_spike_test.goextracts shell blocks from README docs and runs them in a fresh Docker container. It removes infra images first to exercise the real pull path.
- Contributor-only release work: cllama, claw-api, clawdash, claw-wall, and hermes-base still use Docker buildx workflows for publishing. Operators should not reach for raw docker commands; they should use
claw pull,claw build,claw up, andclaw down. - User-defined
healthcheck:inclaw-pod.ymltakes precedence over driver defaults. The override happens incompose_emit.go— checkserviceOut["healthcheck"]before applyingresult.Healthcheck. Service.Composein the pod parser preserves all non-x-clawcompose keys as a deep-copiedmap[string]interface{}. This is how user healthchecks, depends_on, command, etc. flow through.- Releases: use
gh release createwith semver tags. cllama has its own tag namespace (e.g.v0.1.0) published from the submodule repo. ghcr.io packages default to private; must be set public via GitHub UI after first push. Pre-builtclawbinaries are published viagoreleaser(.goreleaser.ymlis in-tree) — do not suggest adding goreleaser, it already exists.install.shdownloads the latest release with checksum verification;claw updatere-runs it. - Before release work:
git fetch --tags. Local tag list can lag GitHub releases significantly (e.g. v0.5.0 lived on GitHub while local tags stopped at v0.2.5). cmd/claw/skill_data/SKILL.mdis a tracked mirror ofskills/clawdapus/SKILL.mdforgo:embedin CI. Keep in sync viago generate ./cmd/claw/...(also runs in the goreleaser before hook). Do not add it back to.gitignore—go vet/CI builds need it present at checkout time.claw-apinow has its own publication workflow (.github/workflows/claw-api-image.yml). Source checkouts now use the same pinned refs as releases; if a pinned repo-local infra tag is not published yet, contributors must build/tag that image explicitly instead of relying on hidden fallback behavior.claw-wallnow has a publication workflow alongside the existing injected sidecar path. Keep end-user docs on the four-verb surface; raw buildx commands are contributor-only release tooling.hermes-baseimage is built fromdockerfiles/hermes-base/and published toghcr.io/mostlydev/hermes-base:<tag>(e.g.v2026.5.16-claw.3). It installshermes-agent[messaging,cron]from the pinned upstream tag, then runspatch-hermes-runtime.pyto apply compatibility fixes. The patch disables themembersandvoice_statesDiscord intents, makes slash-command sync non-blocking (best-effort with timeout), setsallowed_mentions=discord.AllowedMentions(replied_user=False)on allchannel.send()calls that carry a reply reference, letsHERMES_DEFAULT_AGENT_IDENTITYreplace the upstreamYou are Hermes Agentidentity while retaining Hermes memory/session/skill guidance, makes Hermes Discord tool-only mode prefersend_messagewithout dropping plain final replies, and keeps Hermes memory files bounded and host-readable. Without the reply-mention fix, Hermes's reply feature auto-pings the original author, which in multi-agent pods creates mention loops even whenDISCORD_REQUIRE_MENTION=true. Build:docker buildx build --platform linux/amd64,linux/arm64 -t ghcr.io/mostlydev/hermes-base:v2026.5.16-claw.3 --push dockerfiles/hermes-base/.x-claw.masterauto-injects aclaw-apiservice into compose. The master claw gets a bearer token baked into itsfeeds.jsonvia theauthfield, and aCLAW_API_URLenv var pointing at the in-pod API. Feed auth flows:claw up→feeds.jsonwithauth→ cllama fetcher sendsAuthorization: Bearerheader →claw-apivalidates via principals.json.- Alert thresholds are configurable via
CLAW_ALERT_*env vars on the host.claw upforwards them into the auto-injectedclaw-apicontainer. - Prefer reading the code paths above before relying on plan documents.
- When changing runtime behavior, update tests in the same area if they exist.
- If a behavior is reflected in generated artifacts, inspect both the source logic and the generated output expectations in tests.
- Be careful with the working tree: this repo is often mid-change, and unrelated files may already be modified.
- Site is a VitePress app at
site/. Not a submodule — it lives in this repo. - Auto-deploys to
clawdapus.devon merge to master whensite/**changes (.github/workflows/deploy-site.yml). - Sidebar/nav config:
site/.vitepress/config.mts. Guide pages:site/guide/. Top-level pages:site/index.md,site/manifesto.md,site/changelog.md. - Changelog:
site/changelog.mdis manually maintained. Release notes do NOT sync from GitHub releases automatically — add an entry tosite/changelog.mdwhen cutting a release or landing significant features on master.