Skip to content

Propose ref writers: who may push a ref, and how jobs inherit it - #298

Open
nishu-builder wants to merge 3 commits into
mainfrom
claude/upbeat-cori-xk77fg
Open

nishu-builder wants to merge 3 commits into
mainfrom
claude/upbeat-cori-xk77fg

Conversation

@nishu-builder

@nishu-builder nishu-builder commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

design/ref-writers.md covers who can push a ref, and how jobs pass that on. Right now any worker can push any ref.

  • Protected refs live in namespaces, refs/caos/protected/<ns>/, each with one writers list. writers is 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.
  • Writers sign their pushes over the <old> <new> <ref> moves. There are no expiries.
  • Jobs sign with agent keys: agent(ns) = HMAC(HMAC(<writer key>, "caos agent"), <ns>), listed in the namespace's .caos/agents under their writer. An agent can move refs but can't change the lists.
  • The seed sits in the secret store, granted to llm-step, run-and-update-ref and std/actor. For the namespace a request names in X-Caos-Write, the server injects only agent(<ns>), and the sub-runs it starts can't name another namespace.
  • A conversation and its subagents share a namespace, so one change adds or removes a writer for all of them. Several writers can drive one conversation. Each uses their own key and agent, from a tui or a Claude cloud session.
  • An actor's state branch (std/actor) also lives in a namespace, at refs/caos/protected/<ns>/actors/<name>. Only the wrapper's finish gets 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

  1. this PR: design doc
  2. Ref writers, server side: the pre-receive hook, run tokens, admission #303: server
  3. Ref writers, client side: keys, namespaces and writers from caos-cli #304: caos-cli
  4. Ref writers for conversations and actors: namespaces, delegation, and closing the rest #305: conversations and actors

🤖 Generated with Claude Code

https://claude.ai/code/session_01NzY2JJGk9nTMG6gu8dZXpc

@nishu-builder nishu-builder changed the title Design: ref writers (who may push a ref, and how jobs inherit it) Ref writers: who may push a ref, and how jobs inherit it Oct 5, 2026
@nishu-builder
nishu-builder force-pushed the claude/upbeat-cori-xk77fg branch from b2ec3ec to 4331b99 Compare October 5, 2026 04:37
@nishu-builder
nishu-builder force-pushed the claude/upbeat-cori-xk77fg branch from 4331b99 to 9118752 Compare October 5, 2026 07:23
@nishu-builder nishu-builder changed the title Ref writers: who may push a ref, and how jobs inherit it Propose ref writers: who may push a ref, and how jobs inherit it Oct 5, 2026
@nishu-builder
nishu-builder added this pull request to stack #307 October 5, 2026 10:11
@nishu-builder
nishu-builder force-pushed the claude/upbeat-cori-xk77fg branch 3 times, most recently from 7217aad to 219af13 Compare October 6, 2026 02:13
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
@nishu-builder
nishu-builder force-pushed the claude/upbeat-cori-xk77fg branch from 219af13 to 4b1022b Compare October 6, 2026 02:18
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
Comment thread design/ref-writers.md
## 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`.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do this instead of having it be a secret? do we have a notion of client secrets anywhere?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants