@awebai/oats 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +380 -0
  3. package/bin/oats.mjs +3294 -0
  4. package/capabilities/oats-authoring/oats.json +12 -0
  5. package/capabilities/oats-aweb/bin/oats-aweb.mjs +297 -0
  6. package/capabilities/oats-aweb/injects/aweb.md +55 -0
  7. package/capabilities/oats-aweb/oats.json +47 -0
  8. package/capabilities/oats-aweb/package.json +20 -0
  9. package/capabilities/oats-jira/bin/oats-jira.mjs +40 -0
  10. package/capabilities/oats-jira/injects/jira.md +10 -0
  11. package/capabilities/oats-jira/oats.json +22 -0
  12. package/capabilities/oats-jira/package.json +25 -0
  13. package/capabilities/oats-jira/skills/jira-tasks/SKILL.md +176 -0
  14. package/capabilities/oats-linear/README.md +234 -0
  15. package/capabilities/oats-linear/bin/oats-linear-hook.mjs +32 -0
  16. package/capabilities/oats-linear/bin/oats-linear.mjs +344 -0
  17. package/capabilities/oats-linear/injects/linear.md +8 -0
  18. package/capabilities/oats-linear/oats.json +24 -0
  19. package/capabilities/oats-linear/package.json +29 -0
  20. package/capabilities/oats-linear/skills/linear-tasks/SKILL.md +217 -0
  21. package/capabilities/oats-linear/test/oats-linear.test.mjs +168 -0
  22. package/capabilities/oats-okf/agents/memory-harvest.md +25 -0
  23. package/capabilities/oats-okf/bin/oats-okf.mjs +283 -0
  24. package/capabilities/oats-okf/injects/okf.md +62 -0
  25. package/capabilities/oats-okf/oats.json +20 -0
  26. package/capabilities/oats-okf/package.json +22 -0
  27. package/capabilities/oats-okf/skills/memory-harvest/SKILL.md +100 -0
  28. package/capabilities/oats-okf/skills/okf/SKILL.md +107 -0
  29. package/capabilities/oats-okf/skills/okf/scripts/okf-validate.mjs +123 -0
  30. package/capabilities/oats-review/agents/reviewer/AGENTS.md +53 -0
  31. package/capabilities/oats-review/agents/reviewer/soul.yaml +6 -0
  32. package/capabilities/oats-review/injects/review.md +68 -0
  33. package/capabilities/oats-review/oats.json +10 -0
  34. package/capabilities/oats-review/skills/code-review/SKILL.md +44 -0
  35. package/capabilities/oats-review/skills/security-review/SKILL.md +59 -0
  36. package/docs/capabilities.md +505 -0
  37. package/docs/capability-manifest.schema.json +223 -0
  38. package/docs/configuration.md +482 -0
  39. package/docs/conventions.md +73 -0
  40. package/docs/design/desktop-ux-plan.md +362 -0
  41. package/docs/design/package-engine-contract.md +813 -0
  42. package/docs/design/package-runtime-api.md +414 -0
  43. package/docs/desktop-cli-api.md +89 -0
  44. package/docs/desktop-succession.md +51 -0
  45. package/docs/desktop.md +187 -0
  46. package/docs/implementation.md +282 -0
  47. package/docs/integrations.md +123 -0
  48. package/docs/knowledge-theory.md +97 -0
  49. package/docs/knowledge.md +139 -0
  50. package/docs/layers.md +110 -0
  51. package/docs/migration-from-oas.md +122 -0
  52. package/docs/oats-config.schema.json +140 -0
  53. package/docs/oats-lock.schema.json +175 -0
  54. package/docs/oats-package.schema.json +129 -0
  55. package/docs/packages.md +442 -0
  56. package/docs/release-lane.md +132 -0
  57. package/docs/release-notes/v0.18.2.md +79 -0
  58. package/docs/release-notes/v0.18.3.md +63 -0
  59. package/docs/release-notes/v0.18.4.md +65 -0
  60. package/docs/release-notes/v0.18.5.md +66 -0
  61. package/docs/release-notes/v0.18.6.md +87 -0
  62. package/docs/release-notes/v0.19.0.md +186 -0
  63. package/docs/release-notes/v0.19.1.md +24 -0
  64. package/docs/release-notes/v0.19.2.md +32 -0
  65. package/docs/release-notes/v0.19.3.md +16 -0
  66. package/docs/release-notes/v0.19.4.md +12 -0
  67. package/docs/release-notes/v0.20.0.md +89 -0
  68. package/docs/release-notes/v0.22.0.md +180 -0
  69. package/docs/souls-and-instances.md +344 -0
  70. package/injects/framework-workspace.md +7 -0
  71. package/injects/instance-boundary.md +43 -0
  72. package/injects/local-soul.md +19 -0
  73. package/injects/oats.md +11 -0
  74. package/injects/work-attached.md +16 -0
  75. package/injects/work-checkout.md +12 -0
  76. package/injects/work-workspace.md +22 -0
  77. package/injects/work-worktree.md +13 -0
  78. package/lib/core.mjs +6792 -0
  79. package/lib/packages.mjs +1375 -0
  80. package/lib/tmux-config.mjs +35 -0
  81. package/package-catalog.json +44 -0
  82. package/package.json +55 -0
  83. package/packages/record/README.md +151 -0
  84. package/packages/record/bin/capture.mjs +256 -0
  85. package/packages/record/bin/recall.mjs +102 -0
  86. package/packages/record/bin/setup.mjs +281 -0
  87. package/packages/record/bin/turn-record.mjs +47 -0
  88. package/packages/record/docs/turn-record-sot.md +350 -0
  89. package/packages/record/lib/canonical.mjs +151 -0
  90. package/packages/record/lib/capture-aw.mjs +179 -0
  91. package/packages/record/lib/capture-cc.mjs +322 -0
  92. package/packages/record/lib/formats.mjs +296 -0
  93. package/packages/record/lib/ignore.mjs +155 -0
  94. package/packages/record/lib/index-db.mjs +524 -0
  95. package/packages/record/lib/project-aweb.mjs +251 -0
  96. package/packages/record/lib/segments.mjs +186 -0
  97. package/packages/record/lib/store.mjs +447 -0
  98. package/packages/record/lib/tags.mjs +114 -0
  99. package/packages/record/package.json +45 -0
  100. package/packages/record/test/vectors/README.md +34 -0
  101. package/packages/record/test/vectors/aweb-projection-v1.json +231 -0
  102. package/packages/record/test/vectors/journal-merge-v1.json +261 -0
  103. package/packages/record/test/vectors/turn-id-v1.json +152 -0
  104. package/packages/record/test/vectors/validate.mjs +391 -0
  105. package/skills/integration-authoring/SKILL.md +76 -0
  106. package/skills/oats/SKILL.md +151 -0
  107. package/skills/oats-config/SKILL.md +162 -0
  108. package/skills/oats-getting-started/SKILL.md +159 -0
  109. package/skills/oats-packages/SKILL.md +180 -0
  110. package/skills/oats-support/SKILL.md +79 -0
  111. package/skills/skill-craft/SKILL.md +109 -0
  112. package/skills/soul-craft/SKILL.md +109 -0
@@ -0,0 +1,100 @@
1
+ ---
2
+ name: memory-harvest
3
+ description: >-
4
+ Protocol for the memory-harvest agent: promote a live instance's pending
5
+ notes into its soul — knowledge concepts into the right bundle sections,
6
+ procedure-shaped notes into soul skills (new or maintained) — then deliver
7
+ the way the briefing's custody requires and retire. Use when you are a
8
+ memory-harvest instance, or when manually promoting notes/ into a soul.
9
+ Covers the promote/merge/drop decision, knowledge-vs-skill routing, index and
10
+ log discipline, and the three delivery paths.
11
+ ---
12
+
13
+ # Memory harvest — promoting notes into the soul
14
+
15
+ You process the pending `notes/` of a **live, still-running instance**. Its
16
+ notes are promotion candidates. Your job is judgment plus bookkeeping, then
17
+ getting out of the way.
18
+
19
+ ## Ground rules
20
+
21
+ - **Your briefing names your work mode, your soul paths and your finish — it is
22
+ the authority, not this skill.** Custody differs: an ordinary repo-resident
23
+ soul harvests ATTACHED to the source instance's work tree, a workspace-mode
24
+ soul harvests in a WORKTREE of the soul's own home repo, and an uncommitted
25
+ local soul has nothing to commit at all. Read the briefing first; what follows
26
+ is the craft that is the same in all three.
27
+ - **Touch ONLY the soul dirs named in your briefing and the source `notes/`
28
+ files. Nothing else.** When you are attached, the tree's owner keeps working
29
+ while you run.
30
+ - The source instance is alive but cannot be interviewed. Judge notes on
31
+ what they say, not what they might have meant.
32
+ - Never embellish. You move and merge claims. You do not strengthen them.
33
+
34
+ ## Per note: three outcomes
35
+
36
+ Judge each note against the promotion bar — **durable AND would change what
37
+ a future instance of this soul does**. Session trivia, one-off fixes, and
38
+ anything derivable from the repo in seconds fail the bar. The source
39
+ instance captured without judging; judging is exactly your job:
40
+
41
+ - **Promote** — move it into the right home (see routing below), fix links,
42
+ update the section index listing.
43
+ - **Merge** — fold into an existing concept or skill, delete the note.
44
+ - **Drop** — delete it, log one line saying why.
45
+
46
+ ## Routing: knowledge vs skill
47
+
48
+ The shape of the content decides where it lives:
49
+
50
+ | Note contains | Home | Test |
51
+ |---|---|---|
52
+ | A fact, decision, gotcha, reference | `knowledge/<section>/` | "future instances should KNOW this" |
53
+ | A repeatable procedure (steps to run again) | `skills/<name>/SKILL.md` | "future instances should DO this the same way" |
54
+ | A correction to an existing procedure | the existing skill's Gotchas | maintenance, not new knowledge |
55
+ | Both (a lesson that implies a procedure) | knowledge concept + skill references it | split, link them |
56
+
57
+ For skill work follow the **skill-craft** skill (trigger-rich description,
58
+ procedure, gotchas). New skills need a clear repeat-use case — a one-off fix
59
+ is a Lesson, not a skill.
60
+
61
+ ## Types when promoting
62
+
63
+ `type` is freeform (consumers tolerate unknown types). Conventions: a
64
+ `Finding` (unproven observation) that passes the bar becomes a `Lesson`.
65
+ A `Decision` promotes only if it binds future incarnations — task-scoped
66
+ decisions die with the task. `Playbook` = repeatable steps kept as
67
+ knowledge; if instances should RUN it the same way every time, it wants to
68
+ be a skill instead. Souls also grow role-specific types and sections — list
69
+ new sections in the bundle index and log the growth.
70
+
71
+ ## Bookkeeping (non-negotiable)
72
+
73
+ 1. Every promoted concept: correct frontmatter, listed in its section's
74
+ `index.md`, one `log.md` entry per outcome (Creation/Update/Removal —
75
+ okf skill has the conventions).
76
+ 2. Skill changes: log in the soul's `knowledge/log.md` too
77
+ (`**Update**: skills/x — ...`).
78
+ 3. **Delete processed notes from the source `notes/` dir** — promoted,
79
+ merged, and dropped alike. Leftovers get re-harvested next commit.
80
+ 4. Validate: run the okf skill's `scripts/okf-validate.mjs <bundle> --strict`
81
+ — must pass.
82
+
83
+ ## Finish
84
+
85
+ Always: DELETE the notes you processed from the source `notes/` dir, so they are
86
+ never harvested twice. Then deliver the way your briefing says, because that is
87
+ what your custody allows:
88
+
89
+ 1. **Attached to the source work tree** (the usual case — a repo-resident soul):
90
+ one commit on that shared tree with everything you changed, message prefixed
91
+ `memory-harvest:` — e.g.
92
+ `memory-harvest: 2 lessons + 1 skill gotcha from worker-x notes`.
93
+ 2. **Worktree of the soul's home repo** (workspace-mode source): the same single
94
+ commit on your own branch, then push it and open a PR. Never merge it, and
95
+ never push to that repo's main branch — its owners review soul changes.
96
+ 3. **Uncommitted local soul**: nothing to commit. Your edits to the soul ARE the
97
+ delivery; they take effect for the next instance immediately.
98
+
99
+ Then `oats retire <your-instance> --self` from your home. Do not linger — where
100
+ you are attached, the tree belongs to its owner.
@@ -0,0 +1,107 @@
1
+ ---
2
+ name: okf
3
+ description: >-
4
+ Open Knowledge Format (OKF) craft: how to author, maintain, consume, and
5
+ validate OKF knowledge bundles (directories of markdown concepts with YAML
6
+ frontmatter, per Google Cloud's OKF v0.1 spec). Use when writing or editing
7
+ concepts in a knowledge/ bundle or notes/, adding or renaming concept files,
8
+ updating index.md or log.md, answering questions from a bundle, triaging a
9
+ knowledge inbox, or when asked to validate a bundle. This skill is HOW to do
10
+ OKF well; instance session protocol lives in the okf AGENTS.md injection,
11
+ and promotion judgment in the memory-harvest skill.
12
+ ---
13
+
14
+ # OKF craft — author, maintain, consume
15
+
16
+ An OKF **bundle** is a directory tree of markdown files. Each non-reserved `.md`
17
+ file is **one concept**; links between files form the knowledge graph. No
18
+ database, no SDK — plain git-versionable text. Spec: OKF v0.1 (Google Cloud).
19
+ In this fleet: `soul/knowledge/` is a bundle; instance `notes/` files are
20
+ concepts that will be harvested into one.
21
+
22
+ ## The format in one screen
23
+
24
+ - **Concept = one file.** Concept ID = path minus `.md`. Small and specific
25
+ beats long and general — split rather than grow.
26
+ - **Frontmatter** (`---` delimited): only **`type`** is required (short,
27
+ freeform — the spec ships no vocabulary. Fleet core: `Lesson`, `Decision`,
28
+ `Playbook`, `Reference`; souls also grow role-specific types like
29
+ `Area Guide` or `Roadmap` — see the memory-harvest skill for routing).
30
+ Recommended,
31
+ in order: `title`, `description` (ONE sentence — it's what index listings
32
+ and skimming agents see), `resource` (URI, only if a real asset backs the
33
+ concept), `tags` (YAML list), `timestamp` (ISO date of last meaningful change).
34
+ - **Links** are ordinary markdown, keep the `.md`, prefer bundle-root-absolute:
35
+ `[clearing playbook](/playbooks/clearing-fields.md)`. Links are untyped
36
+ directed edges; the surrounding prose carries the relationship's meaning.
37
+ - **Reserved files** at any level: `index.md` (navigation) and `log.md`
38
+ (history). They carry **no `type`**; only the bundle-root `index.md` may
39
+ have frontmatter, and only `okf_version: "0.1"`.
40
+ - **Conventional headings** when applicable: `# Schema`, `# Examples`,
41
+ `# Citations` (numbered external sources backing claims).
42
+
43
+ ## Honesty rules (non-negotiable)
44
+
45
+ - **Never invent** a `resource`, `timestamp`, or `description` — leave a field
46
+ out rather than guess it.
47
+ - Every claim you write down should be something you verified or observed;
48
+ cite sources under `# Citations` when the claim came from outside.
49
+ - Never create a link to a concept you didn't create or verify exists —
50
+ except deliberate not-yet-written knowledge, which is allowed by spec but
51
+ should be rare and intentional.
52
+ - **Supersede, don't silently rewrite.** When a concept's meaning changes,
53
+ update it AND log the change; when it's wrong, correct it and say so in
54
+ log.md (`**Fix**: …`). History must stay reconstructible.
55
+
56
+ ## Maintaining a bundle
57
+
58
+ **Adding a concept:**
59
+ 1. Write the file in the right section dir with valid frontmatter.
60
+ 2. Link it to/from related concepts (edit those files' bodies).
61
+ 3. Add a line to the section's `index.md`: `* [Title](file.md) - description`.
62
+ 4. Append to the bundle's `log.md` (see conventions below).
63
+
64
+ **Renaming/moving a concept:** update **every inbound link** — search the
65
+ whole bundle for the old path (`grep -rn "old-name.md" <bundle>`) — EXCEPT
66
+ links inside historical `log.md` entries: never rewrite log history; dangling
67
+ links there are expected.
68
+
69
+ **Removing:** delete the file, remove its index.md line, fix inbound links,
70
+ log a `**Removal**` or `**Deprecation**` entry saying why.
71
+
72
+ **log.md conventions** (newest first, `## YYYY-MM-DD` headings):
73
+ `* **Creation|Update|Removal|Fix|Deprecation|Harvest|Triage**: prose with
74
+ [links](/path.md).` One line per event; the bold word makes logs greppable.
75
+
76
+ **index.md discipline:** every concept reachable from an index; descriptions
77
+ in listings match the concept's frontmatter `description`. Indexes are
78
+ navigation, not content — keep them to listings.
79
+
80
+ ## Consuming a bundle (answering from knowledge)
81
+
82
+ 1. **Index-first, always.** Start at the root `index.md`; follow only links
83
+ relevant to the question. Never bulk-read a bundle — progressive
84
+ disclosure is the point of the format.
85
+ 2. Frontmatter (`type`, `tags`, `description`) is the quick filter layer;
86
+ open bodies only for concepts that survive the filter.
87
+ 3. `log.md` answers "what changed recently" — check it when freshness matters.
88
+ 4. Cite concepts by path when reporting answers.
89
+ 5. Tolerate imperfection: unknown types, broken links, missing indexes are
90
+ never a reason to reject or ignore a bundle — that permissiveness is spec.
91
+
92
+ ## Validating
93
+
94
+ Run the bundled validator (node, no deps) after non-trivial maintenance:
95
+
96
+ ```bash
97
+ node <skill-dir>/scripts/okf-validate.mjs <bundle-dir> # conformance
98
+ node <skill-dir>/scripts/okf-validate.mjs <bundle-dir> --strict # + producer lints
99
+ ```
100
+
101
+ - **Conformance errors** (must fix): unparseable/missing frontmatter, missing
102
+ or empty `type`, reserved files carrying a `type`.
103
+ - **Producer lints** (`--strict`, should fix in bundles you produce): broken
104
+ intra-bundle links (log.md exempt), links missing `.md`, concepts
105
+ unreachable from any index.md, missing `title`/`description`.
106
+
107
+ Lints in a bundle you're *consuming* are noise — read on regardless.
@@ -0,0 +1,123 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * okf-validate.mjs — OKF v0.1 bundle validator (no dependencies).
4
+ *
5
+ * Usage: node okf-validate.mjs <bundle-dir> [--strict] [--json]
6
+ *
7
+ * Conformance (errors): frontmatter parses; non-empty `type` on concepts;
8
+ * reserved files (index.md, log.md) carry no `type`.
9
+ * Producer lints (--strict, warnings): broken intra-bundle links (log.md exempt),
10
+ * links missing .md, concepts unreachable from any index.md, missing title/description.
11
+ * Exit: 0 conformant, 1 errors (or warnings with --strict), 2 usage.
12
+ */
13
+ import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
14
+ import { join, relative, resolve, dirname, posix } from "node:path";
15
+
16
+ const args = process.argv.slice(2);
17
+ const strict = args.includes("--strict");
18
+ const asJson = args.includes("--json");
19
+ const dir = args.find((a) => !a.startsWith("--"));
20
+ if (!dir || !existsSync(dir)) { console.error("usage: okf-validate.mjs <bundle-dir> [--strict] [--json]"); process.exit(2); }
21
+ const root = resolve(dir);
22
+
23
+ const files = [];
24
+ (function walk(d) {
25
+ for (const e of readdirSync(d, { withFileTypes: true })) {
26
+ if (e.name.startsWith(".")) continue;
27
+ const p = join(d, e.name);
28
+ if (e.isDirectory()) walk(p);
29
+ else if (e.name.endsWith(".md")) files.push(p);
30
+ }
31
+ })(root);
32
+
33
+ const errors = [], warnings = [];
34
+ const rel = (p) => relative(root, p).split("\\").join("/");
35
+ const isReserved = (p) => ["index.md", "log.md"].includes(posix.basename(rel(p)));
36
+
37
+ function parseFrontmatter(text) {
38
+ if (!text.startsWith("---")) return { present: false };
39
+ const m = text.match(/^---\r?\n([\s\S]*?)\r?\n---(\r?\n|$)/);
40
+ if (!m) return { present: true, parsed: false };
41
+ const meta = {};
42
+ for (const line of m[1].split("\n")) {
43
+ if (/^\s*#/.test(line) || !line.trim()) continue;
44
+ const kv = line.match(/^([A-Za-z_][A-Za-z0-9_-]*):\s*(.*)$/);
45
+ if (kv) meta[kv[1]] = kv[2].replace(/\s+#.*$/, "").replace(/^["']|["']$/g, "").trim();
46
+ else if (!/^\s+/.test(line)) return { present: true, parsed: false };
47
+ }
48
+ return { present: true, parsed: true, meta, body: text.slice(m[0].length) };
49
+ }
50
+
51
+ const concepts = new Map(); // rel path -> { meta, body }
52
+ for (const f of files) {
53
+ const r = rel(f);
54
+ const text = readFileSync(f, "utf8");
55
+ const fm = parseFrontmatter(text);
56
+ if (isReserved(f)) {
57
+ if (fm.present && fm.parsed && fm.meta.type) errors.push(`${r}: reserved file must not carry a 'type'`);
58
+ if (fm.present && fm.parsed && posix.basename(r) === "index.md" && r !== "index.md") {
59
+ const keys = Object.keys(fm.meta);
60
+ if (keys.some((k) => k !== "okf_version")) warnings.push(`${r}: only the bundle-root index.md may carry frontmatter`);
61
+ }
62
+ concepts.set(r, { reserved: true, body: fm.parsed ? fm.body : text });
63
+ continue;
64
+ }
65
+ if (!fm.present) { errors.push(`${r}: missing YAML frontmatter`); continue; }
66
+ if (!fm.parsed) { errors.push(`${r}: unparseable YAML frontmatter`); continue; }
67
+ if (!fm.meta.type) errors.push(`${r}: missing or empty required field 'type'`);
68
+ if (strict) {
69
+ if (!fm.meta.title) warnings.push(`${r}: missing recommended field 'title'`);
70
+ if (!fm.meta.description) warnings.push(`${r}: missing recommended field 'description'`);
71
+ }
72
+ concepts.set(r, { meta: fm.meta, body: fm.body });
73
+ }
74
+
75
+ if (strict) {
76
+ // Link checks (log.md bodies exempt) + reachability from index files.
77
+ const reachable = new Set();
78
+ const linkRe = /\[[^\]]*\]\(([^)\s]+)\)/g;
79
+ const resolveLink = (fromRel, target) => {
80
+ if (/^[a-z]+:\/\//i.test(target) || target.startsWith("mailto:")) return null; // external
81
+ const clean = target.split("#")[0];
82
+ if (!clean) return null;
83
+ const abs = clean.startsWith("/")
84
+ ? posix.normalize(clean.slice(1))
85
+ : posix.normalize(posix.join(posix.dirname(fromRel), clean));
86
+ return abs;
87
+ };
88
+ for (const [r, c] of concepts) {
89
+ const body = c.body ?? "";
90
+ const fromLog = posix.basename(r) === "log.md";
91
+ for (const m of body.matchAll(linkRe)) {
92
+ const t = resolveLink(r, m[1]);
93
+ if (t === null) continue;
94
+ const isDir = t.endsWith("/") || concepts.has(posix.join(t, "index.md")) || existsSync(join(root, t)) && statSync(join(root, t)).isDirectory?.();
95
+ if (posix.basename(r) === "index.md" || !fromLog) {
96
+ if (!t.endsWith(".md") && !isDir) { if (!fromLog) warnings.push(`${r}: link missing .md extension: ${m[1]}`); continue; }
97
+ }
98
+ if (fromLog) continue; // history exempt from broken-link lint
99
+ if (t.endsWith(".md") && !concepts.has(t)) warnings.push(`${r}: broken link: ${m[1]}`);
100
+ if (posix.basename(r) === "index.md" && t.endsWith(".md") && concepts.has(t)) reachable.add(t);
101
+ if (posix.basename(r) === "index.md" && isDir) reachable.add(posix.join(t.replace(/\/$/, ""), "index.md"));
102
+ }
103
+ }
104
+ // Reachability: walk index closure (an index that lists a subdir makes that subdir's index reachable).
105
+ for (const [r, c] of concepts) {
106
+ if (c.reserved || reachable.has(r)) continue;
107
+ // root-level concepts listed in root index handled above; report the rest
108
+ const anyIndex = [...concepts.keys()].some((k) => posix.basename(k) === "index.md");
109
+ if (anyIndex) warnings.push(`${r}: unreachable from any index.md`);
110
+ }
111
+ }
112
+
113
+ const conceptCount = [...concepts.values()].filter((c) => !c.reserved).length;
114
+ if (asJson) {
115
+ console.log(JSON.stringify({ bundle: root, concepts: conceptCount, errors, warnings, conformant: errors.length === 0 }, null, 2));
116
+ } else {
117
+ console.log(`OKF validate — ${root}`);
118
+ console.log(` ${conceptCount} concept(s), ${errors.length} error(s), ${warnings.length} warning(s)`);
119
+ for (const e of errors) console.log(` ERROR ${e}`);
120
+ for (const w of warnings) console.log(` warn ${w}`);
121
+ console.log(errors.length === 0 ? (strict && warnings.length ? "PASS (with lints)" : "PASS — conformant") : "FAIL — nonconformant");
122
+ }
123
+ process.exit(errors.length > 0 ? 1 : strict && warnings.length > 0 && process.env.OKF_STRICT_EXIT ? 1 : 0);
@@ -0,0 +1,53 @@
1
+ # reviewer — fresh-eyes post-commit review
2
+
3
+ You are a disposable review instance. You have **no history and no memory by
4
+ design**: every review is a first look, which is your value. You are ATTACHED
5
+ to a developer instance's work tree — the commit is theirs, the tree is
6
+ theirs; you read the diff, you report to your spawner, you retire.
7
+
8
+ **You are ephemeral.** Skip all episodic-state and knowledge-layer upkeep of
9
+ your own — you keep no durable state and promote nothing. Any such instructions
10
+ injected below do not apply to you.
11
+
12
+ ## Operating loop
13
+
14
+ 1. Your TASK.md names the commit to review (or an explicit range). Review
15
+ **only that diff**: `git -C ./work show <sha>` (or
16
+ `git -C ./work diff <base>..<head>` for a range). Read surrounding code
17
+ as needed to judge the diff, but the diff is the review surface — do not
18
+ audit the rest of the tree.
19
+ 2. Run **both** review passes over the diff. **First load the two skills —
20
+ they are your checklists, do not review from memory:**
21
+ - the **code-review** skill (correctness, clarity, tests, design);
22
+ - the **security-review** skill (vulnerabilities, injection,
23
+ secrets, trust boundaries).
24
+ 3. Compose ONE consolidated report:
25
+ - Verdict first: `APPROVE`, `APPROVE WITH NITS`, or `NEEDS CHANGES`.
26
+ - Findings grouped by severity (blocker / important / nit), each with
27
+ file:line and a concrete suggestion.
28
+ - Keep it short. No praise padding. No restating the diff.
29
+ 4. Deliver the report **to your spawner**: the instance named as
30
+ `parentInstance` in your `./instance.json`.
31
+
32
+ - **If a messaging layer is active**, its own instructions are composed into
33
+ these ones — send the report with the command it documents, subject
34
+ `review <short-sha>: <VERDICT>`. Write the report to a temp file first and
35
+ send that file if the command supports it; report bodies contain backticks
36
+ and diff excerpts that inline arguments mangle.
37
+ - **If none is active**, print the full report as your final message. The
38
+ transcript IS the delivery, and your spawner reads it there.
39
+
40
+ Either way that report is your only deliverable — no report files in the
41
+ tree, no PR comments; the spawner owns onward routing.
42
+ 5. Retire yourself: `oats retire <your-instance> --self`.
43
+
44
+ ## Boundaries
45
+
46
+ - **Never edit the work tree.** You are read-only on their branch.
47
+ - Never switch branches, never commit, never push.
48
+ - If the named commit is missing or the range is empty, say so in your report
49
+ and retire cleanly.
50
+ - If the two skills disagree in severity, the stricter verdict wins.
51
+ - If sending fails — or there is no messaging layer at all — print the full
52
+ report as your final message so it lands in the session transcript, then
53
+ retire. The report always gets delivered somewhere.
@@ -0,0 +1,6 @@
1
+ name: reviewer
2
+ kind: capability
3
+ work: attached
4
+ runtime: pi
5
+ model: github-copilot/gpt-5.6-sol:high, openai/gpt-5.6-sol:high
6
+ description: Fresh-eyes post-commit reviewer — reviews one commit's diff with the code-review and security-review skills, reports the verdict to its spawner over the deployment's messaging layer (or in its transcript when there is none), and retires. Ephemeral — no memory, no state tracking.
@@ -0,0 +1,68 @@
1
+ ## Review discipline: oats.review
2
+
3
+ **After every substantive commit, launch the reviewer** — and, when a knowledge
4
+ layer is active, run its promotion step alongside (whatever command that layer
5
+ documents; omit the line entirely if you have no knowledge layer):
6
+
7
+ ```bash
8
+ <your knowledge layer's promotion command> # omit when no knowledge layer is active
9
+ oats spawn reviewer --work attached --work-dir "$PWD/work" \
10
+ --purpose "<short-sha>" \
11
+ --task "Review commit <sha> on branch <branch>. Report to <your-instance> per your operating loop."
12
+ ```
13
+
14
+ - `--purpose "<short-sha>"` gives the reviewer a unique, commit-relevant
15
+ instance name (`reviewer-<short-sha>`); attached mode shares your work tree
16
+ and automatically makes the reviewer your child (attached agents are always
17
+ children of the work-tree owner — no relation flags needed or allowed).
18
+ - The reviewer reviews **that commit's diff only** and reports its verdict
19
+ (`APPROVE` / `APPROVE WITH NITS` / `NEEDS CHANGES`) back to you the way your
20
+ deployment delivers messages: over your messaging layer when one is active,
21
+ and otherwise in its own session transcript, which is where you read it.
22
+ When a messaging layer IS active, do not wait actively — finish your turn and
23
+ go idle; the layer wakes you when the verdict arrives. `NEEDS CHANGES` means
24
+ fix, commit, and re-review before the work is ready.
25
+ - Do not review your own commits in its place — the point is eyes that are
26
+ not yours.
27
+ - Skip only for trivial mechanical commits (typo, lockfile refresh) — when
28
+ in doubt, review.
29
+
30
+ ## Delivery discipline (all OATS developers)
31
+
32
+ - You work in a dedicated worktree on your own branch. **Main only moves
33
+ through PRs** — never push to main.
34
+ - **Single-developer features**: branch from main (`agents/<instance>` or as
35
+ tasked), open the PR yourself (`gh pr create`) when review-clean, then
36
+ **spawn a fresh maintainer instance for it** — one per PR, always, even if
37
+ another oats-expert instance is live:
38
+
39
+ ```bash
40
+ oats spawn oats-expert --purpose "pr<n>" --relation parent --relative-to "$OATS_INSTANCE" \
41
+ --task "Maintainer review of PR #<n>: run your pr-review gates. You own this PR to its terminal outcome — on RETURN stay alive and idle for my fix notice, re-review, repeat; on merge/close record the delivery in your stewardship knowledge and retire yourself. Report verdicts to <your-instance>."
42
+ ```
43
+
44
+ Go idle for the verdict. **The maintainer instance stays alive across
45
+ RETURN rounds** — when you push fixes, notify the SAME maintainer, continuing
46
+ the existing exchange rather than starting a new one; do not spawn another for
47
+ this PR. You never merge to main
48
+ yourself.
49
+
50
+ **Reviewers are the opposite: one per commit, then gone.** The post-commit
51
+ reviewer reviews its one diff, reports its verdict, and retires — it no
52
+ longer exists when you fix its findings. To re-review a fix, spawn a NEW
53
+ reviewer on the fix commit (`--purpose <new-short-sha>`); never message a
54
+ retired reviewer or expect it to follow up.
55
+ - **Multi-developer features**: the coordinator owns the feature branch
56
+ (`feature/<name>`) and the PR. Branch `<you>/<name>` **from the feature
57
+ branch**, push your branch, and tell the coordinator when it is ready —
58
+ the coordinator merges, validates, and reviews the integrated state. Never
59
+ merge into the feature branch yourself.
60
+ - **If you need another developer's unmerged code, ask the coordinator** —
61
+ never fetch or merge a peer's branch yourself. The coordinator
62
+ lands the dependency on the feature branch and tells you to merge the
63
+ feature branch into yours.
64
+ - Quality bar before handing off or opening a PR: the repo's full test/check
65
+ gate green; docs updated with behavior changes.
66
+ - While waiting on the reviewer, the coordinator, or a peer: **do not sleep,
67
+ poll, or busy-wait** — go idle. An active messaging layer wakes you when the
68
+ answer arrives; with none, read the reviewer's own session when it finishes.
@@ -0,0 +1,10 @@
1
+ {
2
+ "capability": "oats.review",
3
+ "version": "1.2.0",
4
+ "compatibility": { "oats": ">=0.16.0" },
5
+ "description": "Post-commit review discipline: a fresh reviewer agent (defined by this capability) reviews each new commit's diff, reports its verdict to its spawner over the deployment's messaging layer (or in its transcript when there is none), and retires — plus the shared developer delivery discipline.",
6
+ "requires": [],
7
+ "agents": ["agents/reviewer"],
8
+ "skills": ["skills/code-review", "skills/security-review"],
9
+ "inject": "injects/review.md"
10
+ }
@@ -0,0 +1,44 @@
1
+ ---
2
+ name: code-review
3
+ description: General code review discipline for reviewing a diff or commit range — correctness, design, readability, tests, and API surface, with severity-ranked, actionable findings. Use when asked to review code changes, a commit, a diff, or a PR for quality.
4
+ ---
5
+
6
+ # Code review
7
+
8
+ Review the CHANGE, not the codebase. The standard (from Google's engineering
9
+ practices): approve when the change **improves overall code health**, even if
10
+ imperfect — demand blockers, suggest the rest.
11
+
12
+ ## Pass order (read the diff twice)
13
+
14
+ **Pass 1 — does it work?**
15
+ - Correctness: logic errors, off-by-one, inverted conditions, wrong operator.
16
+ - Edge cases: empty/null/undefined inputs, zero/negative counts, unicode,
17
+ concurrent access, timeouts, partial failure mid-operation.
18
+ - Error handling: swallowed exceptions, missing cleanup on the error path,
19
+ errors that lie about the cause. Every catch must justify itself.
20
+ - State: mutation of shared state, stale caches, ordering assumptions.
21
+ - Resource lifecycle: files/handles/processes/listeners opened but not closed.
22
+
23
+ **Pass 2 — should it be this way?**
24
+ - Design: is this the simplest change that solves the problem? Flag
25
+ speculative generality and dead configurability.
26
+ - Consistency: does it follow the codebase's existing patterns, naming, and
27
+ error conventions? (Local consistency beats personal preference.)
28
+ - Readability: could a maintainer six months from now follow it without the
29
+ PR description? Names carry meaning; comments explain WHY, not what.
30
+ - API surface: new exports/flags/config keys are forever — are they earned?
31
+ - Tests: does the change carry tests that would FAIL if the logic regressed?
32
+ Tests that mirror the implementation instead of the behavior are findings.
33
+ - Performance: only flag measurable problems (N+1, unbounded growth,
34
+ sync-blocking hot paths) — not micro-optimizations.
35
+
36
+ ## Reporting
37
+
38
+ - Verdict: `APPROVE` / `APPROVE WITH NITS` / `NEEDS CHANGES`.
39
+ - Each finding: `severity — file:line — what + why + concrete fix`.
40
+ Severities: **blocker** (wrong/unsafe/regression), **important** (should
41
+ fix before merge), **nit** (better, not required — prefix "Nit:").
42
+ - Ask questions where intent is unclear instead of asserting a fault.
43
+ - Do not pad: no restating the diff, no praise quotas, no style opinions a
44
+ formatter could hold. If it's clean, say APPROVE and one line why.
@@ -0,0 +1,59 @@
1
+ ---
2
+ name: security-review
3
+ description: Security-focused review of a diff or commit range — injection, secrets, trust boundaries, authz, unsafe deserialization, supply chain, and path/command safety, ranked by exploitability. Use when asked to security-review changes or as the second pass of a full review.
4
+ ---
5
+
6
+ # Security review
7
+
8
+ Review the change as an attacker would read it: every new input is hostile,
9
+ every boundary crossing is an opportunity. Grounded in the OWASP code-review
10
+ model — findings ranked by exploitability, not by pattern-match count.
11
+
12
+ ## Checklist by trust boundary
13
+
14
+ **Inputs (anything the process didn't create itself)**
15
+ - Command injection: user/config/network data reaching `exec`/`spawn`/shell
16
+ strings. Quoting is not escaping; prefer argv arrays. Flag every
17
+ interpolated shell string that carries external data.
18
+ - Path traversal: joins with external segments (`../`), symlink following,
19
+ zip-slip in extraction. Require canonicalize-then-prefix-check.
20
+ - Injection into interpreters: SQL/NoSQL/LDAP/regex/eval/Function/template
21
+ engines fed external strings.
22
+ - Deserialization: YAML/JSON/pickle-style loads of untrusted bytes with
23
+ type resolution or object construction.
24
+ - SSRF: URLs from outside fetched by the server; check scheme/host pinning.
25
+
26
+ **Secrets & data**
27
+ - Hardcoded credentials, tokens, private keys — including in tests, fixtures,
28
+ and example configs. Entropy-looking strings deserve a question.
29
+ - Secrets in logs, error messages, process args (visible in `ps`), URLs.
30
+ - New persistence of sensitive data: is it needed, is it protected, is it
31
+ cleaned up on retire/delete paths?
32
+
33
+ **AuthN/AuthZ**
34
+ - New endpoints/commands/IPC surfaces: who can reach them, and what do they
35
+ authorize against? "Bound to localhost" is a real but WEAK boundary — note
36
+ what a local malicious process could do.
37
+ - Privilege boundaries: does the change let low-trust config/data cause
38
+ high-trust execution (hooks, plugins, migrations, CI)?
39
+ - TOCTOU: check-then-use on files/permissions/state.
40
+
41
+ **Supply chain & execution**
42
+ - New dependencies: are they necessary, pinned, and from expected owners?
43
+ - Downloaded/cloned artifacts: integrity-checked before execution?
44
+ - Anything that writes then executes (temp scripts, curl|sh patterns).
45
+
46
+ **Web-facing (when applicable)**
47
+ - XSS: external strings reaching innerHTML/attributes without escaping.
48
+ - CSRF on state-changing endpoints; CORS wildcards; missing content-type
49
+ discipline on APIs.
50
+
51
+ ## Reporting
52
+
53
+ - Verdict shares the scale: `APPROVE` / `APPROVE WITH NITS` / `NEEDS CHANGES`
54
+ — any credible injection/secret/authz finding is a **blocker**.
55
+ - Each finding: `severity — file:line — attack scenario in one sentence +
56
+ concrete fix`. If you cannot articulate the attack, downgrade to a
57
+ question rather than inventing a threat.
58
+ - Distinguish "exploitable now" from "hardening" — both are reportable,
59
+ only the first blocks.