From 43ef71f3fda92433b007f317590e8a7316584f44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D7=A0=CF=85=CE=B1=CE=B7=20=D7=A0=CF=85=CE=B1=CE=B7=D1=95?= =?UTF-8?q?=CF=83=CE=B7?= Date: Wed, 30 Sep 2026 21:33:20 -0700 Subject: [PATCH] docs: a README shaped like the sister projects' The old one had badges, Usage, a Skills table with the reasoning behind it, and License at the end. The reorg replaced all of that with a list of paths, dropped the Skills section entirely, and left the checks as a two-column table that read like a test plan. This restores the shape and keeps the content current. Badges, with spec-kit swapped for docs-driven. Usage opens with what the product is and the one design fact the rest comes out of, then the tree. The design docs get their own section with the six-row table, plus the four things most likely to catch somebody out, linked: a missing row in a broadcast result, audit redaction being a denylist with no test, a direct permission nullifying every role, and ten minutes being a ceiling. Skills is back, with document added and the reason none of them lists an inventory: org-status takes the repository list from GitHub, add-a-domain resolves its reference domain from the codebase, and document reads the pages that exist. A list written into a skill is right the day it is written. The checks are prose now rather than a table, which is what they are: two scripts that fail the build, and a reader for what neither catches. Contributing and License at the end, matching every sister repository. Also adds .claude/skills/document/README.md, which was the only skill without one. --- .claude/skills/document/README.md | 44 +++++++++ README.md | 157 ++++++++++++++++++++---------- 2 files changed, 151 insertions(+), 50 deletions(-) create mode 100644 .claude/skills/document/README.md diff --git a/.claude/skills/document/README.md b/.claude/skills/document/README.md new file mode 100644 index 0000000..690175a --- /dev/null +++ b/.claude/skills/document/README.md @@ -0,0 +1,44 @@ +# document + +Answers "where does this design go, and what does the page look like?" so writing +one is a prompt rather than a guess about which of twenty files to edit. + +This repository is doc-driven: you design something by writing its page, build it, +then correct the page where building proved it wrong. Same page all three times. +The skill covers the writing. + +## Install + +Nothing to install. The skill lives in this repository and any skills-aware agent +working from the repository root finds it. The checks it runs need [mise] and +[just]. + +## Usage + +Ask in plain language, or invoke it directly with `/document`. + +| Ask | You get | +| ------------------------------------------------ | ----------------------------------------------------------------------- | +| "document how job retries work" | The right component, the existing page if there is one, and a draft | +| "where does the subject naming convention go?" | A component page or `ARCHITECTURE.md`, with the reason | +| "the ten-minute timeout is a ceiling, not a fallback" | The page corrected, with what it said and how you found out | +| "review permissions.md against the house voice" | The tells, quoted, with rewrites | + +## What it does + +Six steps, in order: find whether the page exists, place the subject, work out +what is true from the code rather than from existing prose, write it, link it from +the component's index, then run the checks and `unslop`. + +The placement test is the one worth knowing without the skill: ask whether the +subject is how one repository behaves, or an agreement two of them must both keep. +The first is a page under `components//`, the second belongs in +`ARCHITECTURE.md`, and a rule every repository follows belongs in +`CONSTITUTION.md`. + +[references/voice.md](references/voice.md) carries the writing standard: plain +engineering prose, concrete over abstract, say the tradeoff, and the tells to +avoid. + +[just]: https://just.systems +[mise]: https://mise.jdx.dev diff --git a/README.md b/README.md index 3454d34..e8eb2fa 100644 --- a/README.md +++ b/README.md @@ -1,68 +1,125 @@ -# osapi-io design docs +[![license](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=for-the-badge)](LICENSE) +[![conventional commits](https://img.shields.io/badge/Conventional%20Commits-1.0.0-yellow.svg?style=for-the-badge)](https://conventionalcommits.org) +[![docs driven](https://img.shields.io/badge/docs-driven-blue.svg?style=for-the-badge)](CONTRIBUTING.md) +![gitHub commit activity](https://img.shields.io/github/commit-activity/m/osapi-io/specs?style=for-the-badge) -How the six repositories behind [osapi-io](https://github.com/osapi-io) are -built, and why. No product code here. +# specs -**The product makes a Linux host behave like an appliance.** One binary, one -config file, and you get a REST API, a CLI, a Go SDK and an embedded dashboard -over hostname, DNS, disk, memory, load, packages, services, users, sysctl, cron, -certificates, containers, files and command execution. Across a fleet, not one -box. +The design docs for [osapi-io]. How the six repositories are built and why, in +one place, kept current as they change. No product code here. -The load-bearing design fact: **work reaches a host by being queued, not by -being called.** The controller writes a job and waits; an agent picks it up and -a provider does the work. At-least-once delivery, the idempotency providers owe, -two independent timeouts and a per-host result all come out of that one choice. +## Usage -``` - nats-client ─┐ - ├─→ osapi ──→ osapi-orchestrator - nats-server ─┘ - - gohai (standalone) - osapi-justfiles (every build, by fetch) -``` +[osapi-io] makes a Linux host behave like an appliance. One binary and a config +file give you a REST API, a CLI, a Go SDK and an embedded dashboard over +hostname, DNS, disk, memory, load, packages, services, users, sysctl, cron, +certificates, containers, files and command execution, across a fleet rather +than one box. -## Start here +The design fact everything else follows from: **work reaches a host by being +queued, not by being called.** The controller writes a job and waits; an agent +picks it up and a provider does the work on the machine. At-least-once delivery, +the idempotency providers owe, two independent timeouts and a per-host result +all come out of that one choice. -| If you want to | Read | -| ---------------------------------------- | ---------------------------------------------------------- | -| Understand the product | [osapi](components/osapi/README.md), then its twelve pages | -| Know what breaks if you change something | [ARCHITECTURE.md](ARCHITECTURE.md) | -| Add a page, or know where one belongs | [CONTRIBUTING.md](CONTRIBUTING.md) | -| Know the rules every repository follows | [CONSTITUTION.md](CONSTITUTION.md) | -| See all six repositories | [components/](components/README.md) | +``` +components/ one page per repository, plus a page per subject +ARCHITECTURE.md how the six fit together, and what breaks what +CONSTITUTION.md the rules every repository follows +history/ superseded specs, kept for the record +``` -The four things most likely to surprise you, all written up: -[a missing row in a broadcast result is not an error](components/osapi/agent-identity.md), -[audit redaction is a name-matched denylist with no test](components/osapi/audit.md), -[a direct permission silently nullifies every role](components/osapi/permissions.md), -and [ten minutes is a ceiling, not a fallback](components/osapi/exec.md). +Read [osapi](components/osapi/README.md) first. Twelve subject pages hang off +it, and four of the other five repositories either feed it or consume it. ## Doc-driven development Design something by writing its page. Build it. Correct the page where building -proved it wrong. Same page all three times, which is the point: nothing is -converted from one form into another, because that conversion is where the -design and the docs drift apart. +proved it wrong. Same page all three times, and nothing is converted from one +form into another, because that conversion is where the design and the docs +drift apart. -A feature is an edit to a page here plus a change in the repository it -describes. `/document` is the skill that does the first half. +So a change here is one of four things: -### What keeps it honest +| You are | Change | +| --------------------------------------- | ------------------------------- | +| Designing something new | A new page under its component | +| Changing how something behaves | The page that already covers it | +| Agreeing something between repositories | `ARCHITECTURE.md` | +| Binding every repository to a rule | `CONSTITUTION.md` | -| Check | Fails when | -| ------------------- | ------------------------------------------------------------------------------------------------- | -| `just check-counts` | A count no longer matches the command written beside it, run in the repository the page describes | -| `just check-docs` | A link is dead, a page is missing from its index, or a page reads like a spec instead of docs | -| A reader | They cannot answer the question the page claims to answer | +[CONTRIBUTING.md](CONTRIBUTING.md) has the test for which, and what a page looks +like. -The third is a person, not a script, and it has found more than the other two -together: seven permissions where a page said one, thirteen struct fields where -it said fourteen, a bucket TTL described backwards. +### What keeps it honest + +`just test` runs two scripts and fails the build on either. +[check-counts](scripts/check-counts.py) takes every count in every page and runs +the command written beside it, in the repository that page describes, so a +number that moved breaks CI rather than sitting there wrong. +[check-docs](scripts/check-docs.py) fails on a dead link, a page missing from +its index, or a page that reads like a specification instead of documentation. + +Neither catches prose that drifted from the code. A reader does: hand somebody +the page and nothing else, ask them the question it claims to answer, and fix +what they could not work out. That has found more than both scripts together, +including seven permissions where a page said one, thirteen struct fields where +it said fourteen, and a bucket TTL described backwards. + +## The design docs + +| Repository | Is | +| ------------------------------------------------------------- | -------------------------------------------- | +| [osapi](components/osapi/README.md) | The API and the agent that manage a host | +| [osapi-orchestrator](components/osapi-orchestrator/README.md) | A declarative layer over osapi's SDK | +| [nats-client](components/nats-client/README.md) | A wrapper over the NATS client | +| [nats-server](components/nats-server/README.md) | A NATS server embedded in its consumer | +| [gohai](components/gohai/README.md) | A system fact collection library, standalone | +| [osapi-justfiles](components/osapi-justfiles/README.md) | Shared `just` recipes | + +The four things most likely to catch you out, all written up: a +[missing row in a broadcast result](components/osapi/agent-identity.md) is not +an error and nothing reports it, [audit redaction](components/osapi/audit.md) is +a name-matched denylist with no test behind it, a +[direct permission](components/osapi/permissions.md) silently nullifies every +role on the token, and [ten minutes](components/osapi/exec.md) is a ceiling +rather than a fallback, so a job that needs twenty does not get them. + +## Skills + +Skills here answer questions that span every repository, and carry the +operational knowledge for working in them. + +None of them lists what it describes. `org-status` takes the repository list +from GitHub on each run, `add-a-domain` resolves its reference domain from the +codebase, and `document` reads the component pages that exist rather than a +table of them. An inventory written into a skill is right the day it is written +and wrong after the next change, with nothing marking the moment. + +| Skill | Answers | +| ----------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | +| [document](.claude/skills/document/README.md) | Where a design goes, what the page looks like, and whether one already covers it | +| [org-status](.claude/skills/org-status/README.md) | Open pull requests, Dependabot bumps, security alerts, whether CI is green, and working the merge queue across [osapi-io] | +| [add-a-domain](.claude/skills/add-a-domain/README.md) | Adding an osapi domain: the provider and every layer it has to appear in, in the order that avoids rework | + +Each follows the [Agent Skills] format: a slim `SKILL.md` that routes, with the +detail in reference files an agent reads only when the question calls for them. ## history/ -Fifteen specifications written under a workflow this repo no longer uses. Kept -because they record what was decided and when. Not maintained, and where one -disagrees with a page under `components/`, the page is right. +Fifteen specifications written under a workflow this repository no longer uses. +Kept because they record what was decided and when, not maintained, and where +one disagrees with a page under `components/` the page is right. + +## Contributing + +See the [Contributing](CONTRIBUTING.md) guide for prerequisites, the test for +where a change belongs, what a page looks like, and the PR workflow. + +## License + +The [MIT] License. + +[agent skills]: https://code.claude.com/docs/en/skills +[mit]: LICENSE +[osapi-io]: https://github.com/osapi-io