v0.2.0pre-1.0Apache-2.0

Docs your coding agent
can actually find.

Repo Companion keeps your project docs, patterns, decisions, and standards in one Git-backed store. An agent asks what guidance applies to this task? and gets ranked, cited answers — then proposes changes as a pull request a human merges.

go install github.com/repocompanion/companion/cmd/companion@latest

Requires Go 1.27.3+ ·or download a binary

claude codecompanion mcpstdio

you

Use the companion MCP server for this. Call docs_get_context and tell me where our docs live for this repo. Do not guess paths.

companionok

docs_get_context{}
resultjson
{
  "context": {
    "project": "acme/api",
    "team": "payments",
    "languages": ["go"]
  },
  "area": "projects/acme/api",
  "docs": [
    { "path": "projects/acme/api/README.md",
      "kind": "project-doc", "status": "approved",
      "source": "main", "state": "main" },
    { "path": "projects/acme/api/flows/refund.md",
      "kind": "flow", "status": "approved",
      "source": "changeset cs-mztr4zb3emja", "state": "added" },
    { "path": "org/patterns/messaging/sqs.md",
      "kind": "pattern", "status": "approved",
      "source": "main", "state": "main" }
  ],
  "missing_required": ["projects/acme/api/architecture.md"],
  "active_changesets": [
    { "id": "cs-mztr4zb3emja", "title": "refund flow",
      "pr": 0, "state": "none" }
  ],
  "mirror_rev": "14285dc",
  "mirror_age": "1m ago",
  "warnings": ["GitHub token unavailable; open PRs were not checked"]
}

user, machine, repo_root and the per-field `sources` map are omitted.

agent

The docs for this repo don't live in the code repo. They're in the Companion docs store, under the area projects/acme/api.

PathKindStatusWhere it is
projects/acme/api/README.mdproject-docapprovedon main
projects/acme/api/flows/refund.mdflowapprovedadded in changeset cs-mztr4zb3emja, no PR yet
org/patterns/messaging/sqs.mdpatternapprovedon main (org-wide, not project-specific)

Missing required doc: projects/acme/api/architecture.md.

Canonical layout, relative to projects/acme/api/:

  • Root: only README.md and architecture.md
  • adr/YYYY-MM-DD-<slug>.md: one file per decision
  • flows/<slug>.md, runbooks/<slug>.md, patterns/<slug>.md, standards/<slug>.md
  • Every doc needs YAML frontmatter with id, kind, title, status, owners and last_reviewed

The local mirror is current: rev 14285dc, synced 1 minute ago. I could not check open PRs because no GitHub token is available.

you

Before I write an SQS consumer here: call docs_get_guidance with the task "implement an SQS consumer in Go" and lang go. Summarise the ranked results and cite the path of each one.

companionok

docs_get_guidance{ "task": "implement an SQS consumer in Go", "language": "go" }
resultjson
{
  "results": [
    {
      "id": "sqs-consumer",
      "title": "SQS consumer",
      "path": "org/patterns/messaging/sqs.md",
      "kind": "pattern",
      "status": "approved",
      "scope": "org",
      "score": 4.27,
      "matched_terms": ["sqs", "consumer", "go"],
      "why": "matched in body, headings, refs, title, topics",
      "code_context": [
        {
          "repo": "acme/api",
          "path": "internal/consumer/consumer.go",
          "symbol": "Consume",
          "commit": "e79d9d2",
          "path_status": "valid",
          "symbol_status": "valid",
          "drift_status": "fresh",
          "provider": "go",
          "line": 4,
          "qualified": "consumer.Consume",
          "signature": "func(body string) error"
        }
      ]
    }
  ],
  "task": "implement an SQS consumer in Go"
}

`topics`, `languages`, `last_reviewed` and `reference_impls` are omitted.

agent

Only one result came back, so there is nothing to rank against.

  • SQS consumer — org/patterns/messaging/sqs.md, score 4.27. An approved org-wide pattern for Go; "sqs", "consumer" and "go" appear in its title, headings, body, topics and code references.
  • Example code — internal/consumer/consumer.go:4, the function consumer.Consume with signature func(body string) error, on main at commit e79d9d2. Companion checked that the file and function exist and match the doc.

No ADRs or standards came back, and nothing project-specific under projects/acme/api. The org pattern is the only documented guidance.

The returned snippet was just the doc's heading, so I haven't seen the pattern's actual rules yet. I can fetch org/patterns/messaging/sqs.md and read it before you start.

you

Read the top result with docs_read, and quote only the lines about dead-letter queues and idempotency.

companionok

docs_read{ "path": "org/patterns/messaging/sqs.md" }
resultdocument
---
id: sqs-consumer
kind: pattern
title: SQS consumer
status: approved
topics: [sqs, queue, consumer, messaging]
languages: [go]
owners: [payments]
last_reviewed: 2026-10-26
reference_impls:
  - repo: acme/api
    path: internal/consumer/consumer.go
    symbol: Consume
    kind: function
    ref: main
---
# SQS consumer

Use a dead-letter queue, idempotency keys and bounded concurrency.

## When to use

Use this pattern when a Go service consumes an SQS queue.

## Rules

- MUST configure a dead-letter queue.
- MUST make the handler idempotent.
- SHOULD bound worker concurrency.

## Reference implementations

| Repository | Path | Why |
|---|---|---|
| acme/api | `internal/consumer/consumer.go` | existing consumer in this repo |

Returned as a JSON envelope with `content`, `hash`, `source` and `state`.

agent

Use a dead-letter queue, idempotency keys and bounded concurrency.
- MUST configure a dead-letter queue. - MUST make the handler idempotent.

The first line is the doc's one-line summary; the other two are from the Rules section. That is all the doc has on these topics. It doesn't say how to configure the dead-letter queue or how to derive or store idempotency keys, so you'll have to decide those yourself.

you

Start a changeset called "sqs retry policy" using docs_change_start. Tell me the branch and worktree it created.

companionok

docs_change_start{ "title": "sqs retry policy" }
resultjson
{
  "id": "cs-7i3p5u3fegmq",
  "title": "sqs retry policy",
  "area": "projects/acme/api",
  "branch": "docs/bolacha/projects-acme-api/sqs-retry-policy",
  "path": "/tmp/companion-cli-demo/companion-home/changes/projects-acme-api--sqs-retry-policy",
  "pr_state": "none"
}

`area`, `created_at` and `updated_at` are omitted.

agent

I started changeset cs-7i3p5u3fegmq ("sqs retry policy") in the area projects/acme/api.

  • Branch: docs/bolacha/projects-acme-api/sqs-retry-policy
  • Worktree: /tmp/companion-cli-demo/companion-home/changes/projects-acme-api--sqs-retry-policy

It has no PR yet. Starting it made it the active changeset for the area, so docs writes there now go into it rather than the "refund flow" changeset, which still exists unchanged.

you

Add an ADR with docs_record_decision. Title: "SQS retry policy". Decision: retry three times with exponential backoff, then send to the dead-letter queue. Status: proposed. Show me the canonical path it wrote.

companionok

docs_record_decision{ "title": "SQS retry policy", "context": "The org SQS consumer pattern (org/patterns/messaging/sqs.md) requires that consumers configure a dead-letter queue and use idempotent handlers, but it does not define a retry policy. acme/api consumes SQS via internal/consumer/consumer.go (consumer.Consume).", "decision": "Retry a failed message three times with exponential backoff, then send it to the dead-letter queue.", "consequences": "A message can be processed up to four times (one initial attempt plus three retries), so handlers must be idempotent, as the org pattern already requires. Messages that keep failing go to the dead-letter queue instead of being retried forever, so the dead-letter queue needs monitoring and a way to redrive messages." }
resultjson
{
  "ok": true,
  "path": "projects/acme/api/adr/2026-10-26-sqs-retry-policy.md",
  "pending_sync": true,
  "changeset": {
    "id": "cs-7i3p5u3fegmq",
    "branch": "docs/bolacha/projects-acme-api/sqs-retry-policy",
    "pr_state": "none"
  }
}

The echoed changeset object is trimmed to `id` and `pr_state`.

agent

I recorded the ADR at projects/acme/api/adr/2026-10-26-sqs-retry-policy.md. It went into the "sqs retry policy" changeset and has not been synced yet, so there is no PR.

docs_record_decision has no status parameter, so I could not pass "proposed" myself. I read the file back to check: the frontmatter says status: proposed, which is the default for new ADRs.

The tool also requires a Context and a Consequences section, which you had not given me, so I wrote them myself.

you

Patch that ADR's context section with docs_patch to mention that the payments team's queue standards apply. Pass the current base_rev. If it refuses because base_rev is stale, read the file again and retry.

companionok

docs_patch{ "path": "projects/acme/api/adr/2026-10-26-sqs-retry-policy.md", "base_rev": "4e42676c26dd289f04abe0ca30eb01c3e6448379", "edits": [ { "old": "acme/api consumes SQS via internal/consumer/consumer.go (consumer.Consume).", "new": "acme/api consumes SQS via internal/consumer/consumer.go (consumer.Consume). The payments team's queue standards also apply to this consumer." } ] }
resultjson
{
  "ok": true,
  "pending_sync": true,
  "changeset": {
    "id": "cs-7i3p5u3fegmq",
    "branch": "docs/bolacha/projects-acme-api/sqs-retry-policy",
    "pr_state": "none"
  }
}

The echoed changeset object is trimmed to `id` and `pr_state`.

agent

The patch went through on the first try. The base_rev I passed was 4e42676, the hash returned when I read the ADR back after creating it. It was not stale, so there was no refusal and no retry.

…acme/api consumes SQS via internal/consumer/consumer.go (consumer.Consume). The payments team's queue standards also apply to this consumer.

The new sentence does not link to the standards. The docs list for this project did not include any payments queue standard, so I would need the path to add one to the ADR's related: field.

you

Call docs_change_status and tell me exactly what is staged and on which branch.

companionok

docs_change_status{ "changeset": "cs-7i3p5u3fegmq" }
resultjson
{
  "changeset": {
    "id": "cs-7i3p5u3fegmq",
    "title": "sqs retry policy",
    "branch": "docs/bolacha/projects-acme-api/sqs-retry-policy",
    "pr_state": "none"
  },
  "dirty": null,
  "frozen": false
}

`area`, `path`, `created_at` and `updated_at` are omitted.

agent

Nothing is staged. docs_change_status reports dirty: null, and git status in the worktree shows no staged or modified files. Both changes are already committed locally.

CommitMessageChange
95cf207docs(api): sqs retry policyadded the ADR (+29 lines)
43e90aadocs(api): sqs retry policyedited the same file (+1/−1): the Context patch

PR: none. Frozen: no. Not pushed either — both commits exist only on docs/bolacha/projects-acme-api/sqs-retry-policy until a sync runs.

you

Call docs_change_submit with the message "docs(api): SQS retry policy". Report the result verbatim, including any warnings.

companionblocked

docs_change_submit{ "changeset": "cs-7i3p5u3fegmq", "summary": "docs(api): SQS retry policy" }
resulterror
cannot submit without GitHub authentication

agent

Here is the result verbatim. It returned no warnings and no other output:

cannot submit without GitHub authentication

docs_change_submit has no "message" parameter, so I passed the text as summary. Nothing was pushed, no PR was created, and the changeset is not frozen.

The two commits are still only local, on the changeset branch. This is the same problem as the earlier warning: "GitHub token unavailable; open PRs were not checked".

you

In three sentences: what did you change, where did the guidance come from, and who merges it?

agent

I added one ADR, projects/acme/api/adr/2026-10-26-sqs-retry-policy.md, with status "proposed": it says to retry three times with exponential backoff and then send to the dead-letter queue, and its context says the payments team's queue standards apply.

The guidance came from the org pattern org/patterns/messaging/sqs.md, which requires a dead-letter queue and idempotent handlers, and from its reference implementation, consumer.Consume in internal/consumer/consumer.go.

Companion doesn't let agents merge, so a person has to review and merge the PR — most likely someone from the payments team, since they own these docs. There is no PR yet because the submit failed without GitHub authentication.

A real session: Claude Code against companion mcp, no GitHub token, so the last call is refused.All 9 prompts
Transport
MCP over stdio
Side effects
No daemon, no port
Writes
Draft PRs only
License
Apache-2.0

The problem

Every agent session starts with a guess.

You already wrote the guidance. It is in a wiki, a README, a Slack thread, and one engineer's head. None of that is in the context window, and none of it is in the diff.

Repo Companion treats documentation as a reviewed artifact with an address, an owner, and a diff.

  1. 01

    The agent does not know your docs exist

    It greps for a docs directory, finds a README last touched two years ago, and writes plausible code that ignores every convention you have.

  2. 02

    Decisions live where an agent cannot read

    Confluence, Notion, a wiki, a slide deck. Outside the repository, outside the diff, outside the review that would have caught the mistake.

  3. 03

    AGENTS.md is a file, not a system

    One flat file has no precedence between organization, team, and project rules. No ownership, no review, no references that stay valid as the code moves.

  4. 04

    Guidance drifts from the code it describes

    Paths move, symbols get renamed, and nobody notices until an agent follows a reference that no longer resolves.

How it works

A local read path and a reviewed write path.

Git and GitHub stay the source of truth. The local directory is a cache and a set of working trees — readable by any CLI or MCP client, writable only through a changeset.

Clients

companion CLIhuman terminal
MCP clientClaude Code · Cursor
Exported filesAGENTS.md · llms.txt

Local runtime

runtime.Sessionresolves project, team, languages
guidance + searchranks docs · local BM25
changeset.Manageroverlay · locks · commits

Git & GitHub

repo.git + mainbare clone · read-only checkout
changeset worktrees~/.companion/changes
draft pull requesta human merges
01

One store, with an address for everything

Organization patterns, team standards, project docs, and ADRs live in a single Git repository under org/, teams/, and projects/<owner>/<repo>/. Docs have canonical paths, frontmatter, and owners — not vibes.

02

Reads happen locally

The store is cloned bare, main is checked out read-only, and an overlay exposes your active changeset. Guidance, search, and exports all read the same overlay. No daemon, no port, no telemetry.

03

Writes are pull requests

A change starts a changeset: a branch, a worktree, and a draft PR. An agent can propose, sync, and submit. A human merges under branch protection.

Reads are local. A network call happens only for pull, PR status, review comments, or a PR-specific read.Read the architecture

Ask for guidance

“What applies to this task?”

An agent asks one question instead of guessing at paths. Companion ranks the patterns, ADRs, and standards that apply, explains where they came from, and attaches the reference implementation when the code repository is available.

  • Precedence is explicit. Project rules override team rules, team rules override organization rules, and documented overrides win.
  • Answers are cited. Every result carries its canonical path, its status, and a score.
  • Code references are checked. Paths and symbols are validated against the working tree; drift is reported, not hidden.
Connect an agent
companion guidance "implement an SQS consumer in Go"go
1. SQS consumer [pattern/approved] score=4.27
   org/patterns/messaging/sqs.md
   # SQS consumer
   ref: acme/api@main:internal/consumer/consumer.go
   code: internal/consumer/consumer.go:4 (consumer.Consume) [go]
         path=valid symbol=valid drift=fresh
         func(body string) error

2. Payments queue conventions [standard/approved] score=2.11
   teams/payments/standards/queues.md
   ref: acme/api@main:internal/queue/queue.go

Representative output. Rankings, scores, and reference lines change with your store.

What it does

Small on the surface. Opinionated underneath.

Local BM25 search

Field-weighted ranking with snippets, line numbers, and matched terms. Runs against the overlay, so pending edits are searchable.

Guidance, not grep

companion guidance "<task>" ranks patterns, ADRs, and standards for the job at hand, with project → team → org precedence and explicit overrides.

References that get validated

Documents point at real code. The native Go provider (or optional ctags) checks paths and symbols and reports drift, instead of failing silently.

MCP over stdio

Twenty-plus tools for context, guidance, docs, changesets, reviews, code maps, and pull requests. No port is opened, no service is started.

Works without MCP

Export a managed AGENTS.md block, an llms.txt, or a JSON and Markdown context bundle for agents that only read files.

Explicit changesets

A branch, a worktree, and a draft PR. No background sync, no polling, no auto-push, and no path from an agent to a merge button.

An owl carrying a binder of documentation while a hand stamps a change, next to a branching git graph.
Reads the store, carries the change, hands it over for review.

The companion

It arrives having read the docs.

That is the whole product. The agent starts from your reviewed guidance instead of a plausible guess, writes in a branch, and opens a draft pull request. A person reviews it. The stamp stays yours.

  • Reads what applies. Project, team and organization guidance, ranked for the task at hand.
  • Writes in a branch. A worktree, a commit, a draft PR — main is never touched.
  • Waits for review. Submit marks the PR ready and freezes the changeset.

Safety model

Agents never merge.

Companion is built so that a confident agent cannot quietly rewrite your standards. Branch protection stays the source of truth, and the local machine stays a cache.

The secret scan is a heuristic, not a guarantee. Everything else here is enforced by the code path that writes.

Security model
  • main is read-only locally and protected on GitHub.
  • Every write is committed immediately and scanned for likely secrets before the commit.
  • Document paths reject absolute paths, traversal, .git, and symlink escapes.
  • base_rev refuses to overwrite a newer edit, and a failed write rolls back.
  • Per-area file locks serialize Git work between concurrent CLI and MCP calls.
  • No daemon, service, polling loop, telemetry, or local network port.

Where it fits

Not a replacement for your wiki. A home for the part agents need.

Docs have to live where an agent can read them and a reviewer can see them. That is a narrow requirement, and most documentation platforms were not built for it.

ApproachStrengthWhere it falls short for agents
AGENTS.md in every repoZero setup, lives with the codeDuplicated per repo; org patterns drift; no cross-project review
Confluence / NotionFamiliar authoring and permissionsOutside the review flow; agents need a separate integration
Backstage TechDocsCatalog, ownership, portal UXNeeds a portal and pipeline; agent access is an extra integration
Plain docs-as-codeSimple and transparentAgents still have to guess where to look; no changeset or ranking
Repo CompanionCentral store, local reads, reviewed writesRequires GitHub, Markdown, and a CLI. No web editor.
Read the full comparison, including when it is not a good fit

Install

One binary. One config file.

Companion ships as a single Go binary with no runtime dependency. The MCP server runs over stdio, so there is nothing to host and nothing to expose.

All install options

1 · install the CLI

go install github.com/repocompanion/companion/cmd/companion@latest

Or grab a prebuilt archive for macOS, Linux, or Windows from Releases.

2 · connect your agent

claude mcp add --scope user companion -- companion mcp

Cursor and other MCP clients use the same command with args ["mcp"]. See connect an agent.

Try it offline

Sixty seconds, no account, no token, no network.

The demo script builds a throwaway store, a small Go repository, and a changeset, then checks its own output.