contenox
Browse docs/

Codebase documentation

Point an agent at your source tree and have it write the documentation nobody gets around to: an architecture guide, an onboarding page, a module reference — grounded in the code it actually read, and regenerated by a command instead of a person.

Prerequisites

  • contenox init once in the repository, and a model configured — see Quickstart.

  • An envelope. contenox run fires a mission, and a mission that names no envelope is refused:

    contenox config set default-mission-policy hitl-policy-default.json

Nothing else. local_fs and local_shell are hosted by contenox and carried by the client that runs the agent, so reading your own tree needs no filesystem server registered and no flag enabling it. The workspace is the directory you started the command in.


The agent

.contenox/agents/docs-writer.md:

---
name: docs-writer
description: Writes and updates documentation from the source it read in this repository
tools: Read, Write, Edit, Bash, git.git_diff, git.git_log, git.git_show
---

You document code you have read. A claim you cannot point at a file for does
not go in the document.

PROCEDURE: find the shape of the tree first — `ls` at the top level, then
descend deliberately. Never enumerate blind: exclude `node_modules`, `dist`,
`vendor`, `target` and `.git` by name from every `find`, and pass
`--exclude-dir` to `grep`. Read entry points before helpers, and follow imports
rather than guessing at what a package is for.

Prefer local_fs.read_file over cat and head: it is bounded and it respects the
policy that cat does not. Use the shell for what has no dedicated tool — find,
grep, and running a command whose output you intend to quote.

WRITE the document to the path you were given, creating the parent directory if
it does not exist. Structure it so a reader who has never opened this repository
can find their way: what the thing is, the packages and what each owns, the
paths a request takes through them, and where the state lives.

DO NOT invent. When two readings of the code are both plausible, write the one
you can cite and say plainly that the other is unverified. A confident sentence
about code you did not open is the worst thing you can leave behind.

FINISH with what you wrote, which files you read to write it, and anything you
could not establish from the source.

The tool list is the interesting line. Read, Write and Edit are the local_fs tools; Bash is local_shell; the three git.git_* entries are the read-only half of the git toolset — enough to see what changed, and nothing that can commit it. Omitting tools: entirely would inherit every tool on the machine instead.

contenox agent list      # the next run picks the file up; there is no build step

Recipe 1: an architecture guide

contenox run docs-writer \
  "Read the Go sources under ./internal. Write docs/architecture.md: the top-level packages and what each owns, the data flow between them, and where state is persisted."

The agent lists the tree, reads what it needs, writes the file, and reports what it read. Stdout carries that report — the file is the artifact, and the report is how you know it landed.

Recipe 2: an onboarding page for a new hire

contenox run docs-writer \
  "Read ./README.md, ./docs/ and ./go.mod. Write docs/onboarding.md: what this project does, how to run it locally, the concepts a newcomer needs, and three first tasks that touch real code."

Recipe 3: keep the docs honest after a change

This is the one that pays for the declaration. The agent has git_diff and git_log, so it can establish what moved before deciding what to rewrite:

contenox run docs-writer \
  "The last commit refactored the retry path. Read its diff, then read the current text of every file it touched, then update the affected sections of docs/architecture.md. Change nothing the diff did not."

Or let a merge trigger it. .git/hooks/post-merge:

#!/bin/sh
contenox run docs-writer \
  "Read the diff of the merge that just landed, then update any section of docs/ it made wrong. Change nothing else." \
  --timeout 15m

An agent asked to update rather than regenerate does less damage to a hand-written page, but it will still touch what it believes is stale. Run it on a branch and read the diff it produced — the same way you would review any other automated edit.

Recipe 4: a module reference

contenox run docs-writer \
  "List the exported functions in ./internal/payments. For each, read its signature and doc comment. Write docs/reference/payments.md as a table: Function | Signature | What it does."

The piped form

For a one-off question about a diff, no declaration is involved:

git diff | contenox "which of these changes make docs/architecture.md wrong?"

The diff is the material the question is about, and the answer comes back on stdout. Reach for the pipe when you want to know something; reach for contenox run docs-writer when you want a file written.


Publishing straight to Notion

Register the server once, then grant it to the agent:

contenox mcp add notion https://mcp.notion.com/mcp --auth-type oauth
contenox mcp auth notion

contenox mcp auth is a separate, required step — add registers the server, it does not authenticate it. See Notion as a tool for the full server surface.

Give a second declaration the grant, .contenox/agents/docs-publisher.md:

---
name: docs-publisher
description: Writes documentation from the source and publishes it to Notion
tools: Read, Bash, notion.create_page, notion.update_page, notion.search
mcpServers: [notion]
---

You document code you have read, then publish it.

Read the source you were pointed at before writing a line about it, the same
way you would for a file on disk. Then search Notion for a page with the title
you were given: update it when it exists, create it when it does not. Never
create a second page with a title that is already taken.

Report the page URL and the files you read. Nothing else.
contenox run docs-publisher \
  "Read ./internal. Write an architecture guide and publish it to Notion as 'Architecture: payments-api'."

Note what this declaration does not carry: Write and Edit. It publishes to Notion, so it has no business writing to your disk, and the tool list is where that is settled rather than the prompt.


Two things to know before you script it

A gated call has nobody to ask. There is no terminal in front of contenox run, so a call the envelope gates becomes a durable ask and the run waits on that row until someone answers it with contenox approvals respond — the answer releases the waiting call and the run carries on — or until --timeout (default 30m) tears it down with a non-zero exit. If a documentation run keeps timing out, the envelope gated the write; widen the envelope, not the prompt.

Scope the read. A large repository will not fit in a context window, and an agent told to “read the codebase” spends its budget on node_modules. Name the packages you mean. The bounds it works inside — the context budget, the tool-call ceiling, the loop rounds — live in agents.toml ([chain] token_limit, [policy.compute] max_tool_calls), not in the declaration.

The run leaves a durable record either way:

contenox mission list
contenox mission reports <mission-id>

Esc to close