# AGENTS.md

This repository is a monorepo shipping four Ruby gems around one format: `okf`,
the
baseline that reads, validates, lints, searches and serves Open Knowledge
Format (OKF) v0.2 bundles, and three surfaces over it — an MCP shell, a terminal UI and
an enforcement layer.

**This file is context, routing and reference.** It states what binds every
change, points at where to read, and lists the commands. It explains nothing: the
arguments live in the bundles, which are the harness a contributor works from.
Start with the row for what you are changing.

## Where to go

| working on | guide | bundle |
| --- | --- | --- |
| the baseline gem | [`gems/okf/AGENTS.md`](gems/okf/AGENTS.md) | `okf search @okf <term>` |
| the MCP shell | [`gems/okf-mcp/AGENTS.md`](gems/okf-mcp/AGENTS.md) | `okf search @okf-mcp <term>` |
| the terminal UI | [`gems/okf-tui/AGENTS.md`](gems/okf-tui/AGENTS.md) | `okf search @okf-tui <term>` |
| the enforcement layer | [`gems/okf-pro/AGENTS.md`](gems/okf-pro/AGENTS.md) | `okf search @okf-pro <term>` |
| the plugin, the skills, the resources, or anything binding all four | this file | `okf search @okf-eco <term>` |

`okf search @all <term>` reaches every bundle at once; `rake serve` opens this
repository's own as a graph.

## What binds every change

Four rules to follow unprompted. The argument for each is one link away; these
lines are the whole of what you must obey without reading it.

- **A change starts with a failing test, read failing**, then the code, then the
  same test green and **unedited**. A bug report earns a red test before a patch.
- **Assertions must be able to fail for a real reason.** Run the thing, read
  what it prints, assert *that* — never what you assume the code does.
- **The bundle ships in the same commit as the code it documents.** A file under
  `lib/` that no concept names is a red suite, not a stale document.
- **Don't improve adjacent code**, and add no abstraction for single-use code.
  Match the surrounding style (`.rubocop.yml` — spaced brackets `[ 1, 2 ]`,
  double quotes); remove only orphans your own change created.

Why each, and what they are worth:
[.okf/design/how-a-change-is-proven.md](.okf/design/how-a-change-is-proven.md).

**Commits are attributed to the human maintainer only** — no AI co-author
trailers, no "generated by" lines, in commits or PRs.

If a request is ambiguous, name the interpretations rather than picking one
silently, and push back when a simpler approach exists.

## Map

```
gems/okf/       the baseline gem, registered as plain `@okf`. Floor 2.4; deps
                exactly rack + webrick + minifts. Ships the skill, and its own
                `.okf/` inside the gem
gems/okf-mcp/   the MCP shell: the kernel's capabilities as MCP tools + prompts.
                Floor 2.7 — the `mcp` SDK's — deps exactly `mcp` + `okf`
gems/okf-tui/   the terminal UI: six views over one or many bundles, and the
                registry. Floor 2.4, deps `okf` + the TTY toolkit
gems/okf-pro/   the enforcement layer: `okf pro setup` writes an agent's
                knowledge repo, `okf pro hook` runs one gate against one hook
                event. Floor 2.4, deps exactly `okf`. Its `hook` verb is the one
                place in the repo where exit 1 is *non-blocking* and 2 refuses
plugin/         the Claude Code plugin — generated skill copy, command, curation hook
.claude-plugin/ the marketplace manifest (the repo doubles as the marketplace)
skills/         the skills a generic installer reads: a generated copy of okf's,
                and okf-principles, whose canonical copy this is
.okf/           the ecosystem's map, registered as `@okf-eco` — a concept per
                gem, per plugin item, per skill and per resource, plus the
                format, the decisions and the design that govern them all
.okf.json
                every bundle in the tree, addressable as `@slug`; while you stand
                under this root it *replaces* your global $OKF_HOME registry
Dockerfile      builds gems/okf/ — from a root context, because the gemspec needs .git
Rakefile        a delegator: `rake` runs every gem's default task
```

**A directory under `gems/` is a gem and is named for the gem it ships; anything
at the root is named for what it is.** A new root name has to be forced by an
external consumer — a marketplace path, an installer's discovery walk — or it
belongs under `resources/`.

Never edit `plugin/skills/okf` or `skills/okf`: both are generated by `rake
skill:sync` in the *gem's* Rakefile, and two guards fail the build on drift.

## Commands

Plain `rake`, no bundler — there is no root Gemfile, and `bundle exec rake` here
failing with "Could not locate Gemfile" is the intended answer.

```bash
rake        # every gem's default task, then the repo-level rubocop
rake test   # every gem's suite
rake okf    # validate + lint all five bundles
rake serve  # serve this repo's own .okf as a graph
```

Everything about one gem — its suite, its CLI from a checkout, its floor
container, its release — is in that gem's own guide. A release is cut from the
gem's directory; `rake release` here refuses.

## Reference

| question | read |
| --- | --- |
| why gems live under `gems/`, and what earns a root name | [.okf/decisions/monorepo-layout.md](.okf/decisions/monorepo-layout.md) |
| why there is no root Gemfile, and how CI is split | [.okf/decisions/the-root-is-not-a-gem.md](.okf/decisions/the-root-is-not-a-gem.md) |
| why a sibling ships no exe, and the seam's threat model | [.okf/decisions/one-door-per-sibling.md](.okf/decisions/one-door-per-sibling.md), [.okf/design/extension-points.md](.okf/design/extension-points.md) |
| which of README, AGENTS.md or a bundle a fact belongs in | [.okf/design/where-knowledge-lives.md](.okf/design/where-knowledge-lives.md) |
| what a README may and may not carry | [.okf/design/the-readmes.md](.okf/design/the-readmes.md) |
| the shape of a PR, and what a release PR adds | [.okf/design/pull-requests.md](.okf/design/pull-requests.md) |
| the tag convention across the four gems | [.okf/decisions/release-and-tags.md](.okf/decisions/release-and-tags.md) |
| which obligations nothing enforces, and why that is said out loud | [.okf/design/nothing-runs-it.md](.okf/design/nothing-runs-it.md) |
| what the plugin, the skills and the resources are | [.okf/plugin/](.okf/plugin/), [.okf/skills/](.okf/skills/), [.okf/resources/](.okf/resources/) |

Five bundles: `.okf/` for the ecosystem, one in each gem. A fact that survives
deleting a gem is the ecosystem's. A concept cannot link out of its own bundle,
so a reference across the line names the other in prose — `` `@okf
capabilities/linter` ``.
