Repository navigation
Propose ref writers: who may push a ref, and how jobs inherit it - #298
nishu-builder wants to merge 3 commits into
Conversation
b2ec3ec to
4331b99
Compare
4331b99 to
9118752
Compare
7217aad to
219af13
Compare
Any worker can push any ref today. design/ref-writers.md governs refs by namespace: a `writers` ref lists ed25519 public keys, clients sign each ref move, and jobs get server-issued run tokens scoped by a `writes` arg they can only pass on to runs they create. It works from cloud sessions with one key per writer, a conversation and its subagents live in one namespace, and an actor's state branch lives in one too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzY2JJGk9nTMG6gu8dZXpc
219af13 to
4b1022b
Compare
From Nishad's first read: - refs/caos/w/<id>/ becomes refs/caos/protected/<ns>/, and governed refs are protected refs (caos.unprotectedRef for the one hole). - The writers ref is described as the namespace's history of write access, the namespace label is explained, and the server's enforcement is stated where it applies. - Writer signatures say what <old> <new> <ref> is; run tokens get their own section after them, so neither is used before it is explained. - Alternatives: the list in the commit message, the rules on the namespace's root ref, and git's own signed pushes. The stack on top still implements the previous draft. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzY2JJGk9nTMG6gu8dZXpc
| ## Keys | ||
|
|
||
| Each writer has an ed25519 ref writer key. The private key stays on the | ||
| writer's device, in the checkout's git config as `caos.ref-writer-key`. |
There was a problem hiding this comment.
why do this instead of having it be a secret? do we have a notion of client secrets anywhere?
There was a problem hiding this comment.
It can't be a caos secret, because those only flow one way. You push them to the server, and it injects them into jobs at /secret/<name>; it never returns a value to a client (SPEC, "Secrets"). This key is used by the client itself (caos-cli, caos mcp, the tui) to sign pushes and X-Caos-Write. Jobs don't need it either, because they get run tokens. Giving the server writers' private keys is the alternative the doc rejects.
On client secrets: the only precedent is the secret store's own SecretWriterKey. caos-cli secrets-init keeps it in a 0600 dotfile inside the 0700 secrets directory, not in git config. That's the better model here, since .git/config is 0644 and git config -l prints it. I'd change the doc to a 0600 file per writer, e.g. ~/.config/caos/ref-writer-key, and have the cloud setup line write that same file. Shall I?
Generated by Claude Code
There was a problem hiding this comment.
Update for fc19006: part of my answer above is out of date. Jobs don't get run tokens any more. Each writer's seed, HMAC(<writer key>, "caos agent"), now is a caos secret, and the server injects per-namespace agent keys derived from it (see "Agent keys"). The writer key itself still stays on the client, since the client uses it to sign pushes and to add its agent to namespaces. So the open question is still whether it lives in git config or a 0600 file.
Generated by Claude Code
Jobs sign with per-namespace agent keys derived from the writer's key, listed in .caos/agents. The seed lives in the secret store, granted to the tools that write refs, and the server injects only agent(<ns>) for the namespace a request names in X-Caos-Write. No run tokens, no expiries, no writes arg. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzY2JJGk9nTMG6gu8dZXpc
design/ref-writers.mdcovers who can push a ref, and how jobs pass that on. Right now any worker can push any ref.refs/caos/protected/<ns>/, each with onewriterslist.writersis a chain of commits (the history of write access) and<ns>is the hash of its first one, so nobody can grab a namespace before you or make one you aren't in.<old> <new> <ref>moves. There are no expiries.agent(ns) = HMAC(HMAC(<writer key>, "caos agent"), <ns>), listed in the namespace's.caos/agentsunder their writer. An agent can move refs but can't change the lists.llm-step,run-and-update-refandstd/actor. For the namespace a request names inX-Caos-Write, the server injects onlyagent(<ns>), and the sub-runs it starts can't name another namespace.std/actor) also lives in a namespace, atrefs/caos/protected/<ns>/actors/<name>. Only the wrapper'sfinishgets the agent key; the inner gets nothing. This answers open question 5 in the actor README.The doc is still in review. The PRs stacked on top implement an earlier draft (
refs/caos/w/, "governed", run tokens). They'll be updated once the design settles.Stack
🤖 Generated with Claude Code
https://claude.ai/code/session_01NzY2JJGk9nTMG6gu8dZXpc