Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions adapters/codex/AGENTS.md.snippet
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Vouch — knowledge base

This repo uses **vouch** for durable agent knowledge. The KB lives in
`.vouch/` and is reviewed in PRs like any other code.

## How to remember things

To preserve a fact, decision, or workflow across sessions:

1. Register evidence: `kb_register_source` (or
`kb_register_source_from_path` for a file).
2. Propose a claim that cites it: `kb_propose_claim`. Every claim
MUST cite at least one source or evidence id.
3. For richer write-ups, propose pages: `kb_propose_page` with a
markdown body that references claims.

You **cannot** write durable knowledge directly. Proposals land in
`.vouch/proposed/` and require human approval via `vouch approve`.
This is intentional.

## How to read

- `kb_search` for keyword search.
- `kb_context` to fill a working set for a task ("what does this KB know
about X?").
- `kb_read_*` for specific ids.

## Identity

Set `VOUCH_AGENT=codex` in your env (or the MCP entry's `env:` block) so the
audit log can attribute writes to this host.
7 changes: 7 additions & 0 deletions adapters/codex/install.yaml
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
# OpenAI Codex CLI adapter manifest.
#
# T1 = project-local MCP config at `<project>/.codex/config.toml`.
# Codex reads `<project>/.codex/config.toml` (also `~/.codex/config.toml` for
# user-global). We ship the project-local form so `vouch install-mcp codex`
# doesn't touch home-directory state -- see issue #179 scope decision.
# T2 = AGENTS.md fenced snippet (Codex reads AGENTS.md the way Cursor does).
host: codex
pretty: OpenAI Codex CLI
fence:
begin: "<!-- BEGIN vouch -->"
end: "<!-- END vouch -->"
tiers:
T1:
- { src: config.toml, dst: .codex/config.toml }
T2:
- { src: AGENTS.md.snippet, dst: AGENTS.md, fenced_append: true }
43 changes: 43 additions & 0 deletions tests/test_install_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -480,3 +480,46 @@ def test_installed_wheel_resolves_adapters(tmp_path: Path) -> None:
assert "claude-code" in result["hosts"], (
f"installed copy can't resolve adapters: {result}"
)


# --- codex: T2 AGENTS.md fenced snippet (vouchdev/vouch#385) ---------------


def test_install_codex_t1_writes_config_toml(tmp_path: Path) -> None:
"""T1 produces the project-local .codex/config.toml."""
result = install("codex", target=tmp_path, tier="T1")
assert (tmp_path / ".codex" / "config.toml").is_file()
assert not (tmp_path / "AGENTS.md").exists()
assert result.written and not result.appended


def test_install_codex_t2_creates_agents_md(tmp_path: Path) -> None:
"""T2 appends the fenced AGENTS.md snippet; creates file when absent."""
result = install("codex", target=tmp_path, tier="T2")
assert (tmp_path / ".codex" / "config.toml").is_file()
assert (tmp_path / "AGENTS.md").is_file()
assert "AGENTS.md" in result.written
content = (tmp_path / "AGENTS.md").read_text()
assert "<!-- BEGIN vouch -->" in content
assert "<!-- END vouch -->" in content
assert "VOUCH_AGENT=codex" in content


def test_install_codex_t2_idempotent(tmp_path: Path) -> None:
"""Re-running T2 leaves AGENTS.md unchanged — fence dedup."""
install("codex", target=tmp_path, tier="T2")
content_first = (tmp_path / "AGENTS.md").read_text()
again = install("codex", target=tmp_path, tier="T2")
content_again = (tmp_path / "AGENTS.md").read_text()
assert content_first == content_again
assert "AGENTS.md" not in again.appended


def test_install_codex_t2_appends_to_existing_agents_md(tmp_path: Path) -> None:
"""When AGENTS.md already exists without a fence, the snippet is appended."""
(tmp_path / "AGENTS.md").write_text("# Existing project notes\n")
result = install("codex", target=tmp_path, tier="T2")
assert "AGENTS.md" in result.appended
content = (tmp_path / "AGENTS.md").read_text()
assert content.startswith("# Existing project notes\n")
assert "<!-- BEGIN vouch -->" in content