okf-pro 1.0.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.
- checksums.yaml +7 -0
- data/.okf/contract/containment-directions.md +107 -0
- data/.okf/contract/exit-codes.md +42 -0
- data/.okf/contract/gates-only-at-the-hook-door.md +39 -0
- data/.okf/contract/index.md +10 -0
- data/.okf/contract/silent-skips.md +78 -0
- data/.okf/contract/telemetry-does-not-lie.md +218 -0
- data/.okf/contract/the-contract.md +43 -0
- data/.okf/design/a-comment-is-not-an-implementation.md +85 -0
- data/.okf/design/a-rule-you-can-walk-past.md +68 -0
- data/.okf/design/derivation-that-writes.md +161 -0
- data/.okf/design/failure-modes.md +43 -0
- data/.okf/design/index.md +18 -0
- data/.okf/design/lineage.md +95 -0
- data/.okf/design/structure-laws.md +46 -0
- data/.okf/design/the-residue.md +44 -0
- data/.okf/design/three-laws.md +71 -0
- data/.okf/design/three-pillars.md +48 -0
- data/.okf/index.md +31 -0
- data/.okf/log.md +74 -0
- data/.okf/scaffold/collisions-and-refusals.md +76 -0
- data/.okf/scaffold/index.md +8 -0
- data/.okf/scaffold/no-date-ships.md +41 -0
- data/.okf/scaffold/ownership-not-subject.md +63 -0
- data/.okf/scaffold/the-adopters-manual.md +114 -0
- data/.okf/seam/bundler-scoping.md +45 -0
- data/.okf/seam/identity-not-existence.md +67 -0
- data/.okf/seam/index.md +8 -0
- data/.okf/seam/the-wrapper.md +42 -0
- data/.okf/seam/three-fail-opens.md +44 -0
- data/.okf/testing/drills-over-units.md +41 -0
- data/.okf/testing/fixture-is-a-client.md +35 -0
- data/.okf/testing/index.md +4 -0
- data/.okf/trust/index.md +7 -0
- data/.okf/trust/read-owed-rule.md +45 -0
- data/.okf/trust/scalar-verified.md +48 -0
- data/CHANGELOG.md +187 -0
- data/LICENSE.txt +201 -0
- data/NOTICE +10 -0
- data/README.md +383 -0
- data/lib/okf/plugin.rb +148 -0
- data/lib/okf/pro/attestation.rb +62 -0
- data/lib/okf/pro/audit.rb +161 -0
- data/lib/okf/pro/board/edit.rb +201 -0
- data/lib/okf/pro/board.rb +291 -0
- data/lib/okf/pro/budget.rb +144 -0
- data/lib/okf/pro/bundle_root.rb +241 -0
- data/lib/okf/pro/cli.rb +914 -0
- data/lib/okf/pro/closing.rb +206 -0
- data/lib/okf/pro/conformance.rb +127 -0
- data/lib/okf/pro/conserve.rb +94 -0
- data/lib/okf/pro/event.rb +95 -0
- data/lib/okf/pro/friction.rb +262 -0
- data/lib/okf/pro/guards.rb +92 -0
- data/lib/okf/pro/log/edit.rb +68 -0
- data/lib/okf/pro/log.rb +162 -0
- data/lib/okf/pro/pairing.rb +271 -0
- data/lib/okf/pro/reconcile.rb +76 -0
- data/lib/okf/pro/records.rb +90 -0
- data/lib/okf/pro/scaffold.rb +258 -0
- data/lib/okf/pro/shell_guard.rb +164 -0
- data/lib/okf/pro/snapshot.rb +156 -0
- data/lib/okf/pro/state.rb +174 -0
- data/lib/okf/pro/target.rb +91 -0
- data/lib/okf/pro/template/gem/.claude/hooks/run +119 -0
- data/lib/okf/pro/template/gem/.claude/skills/okf-pro/SKILL.md +233 -0
- data/lib/okf/pro/template/gem/.claude/skills/okf-pro/guides/attribution.md +46 -0
- data/lib/okf/pro/template/gem/.claude/skills/okf-pro/guides/board.md +55 -0
- data/lib/okf/pro/template/gem/.claude/skills/okf-pro/guides/closing.md +21 -0
- data/lib/okf/pro/template/gem/.claude/skills/okf-pro/guides/frontmatter.md +73 -0
- data/lib/okf/pro/template/gem/.claude/skills/okf-pro/guides/okf-rules.md +25 -0
- data/lib/okf/pro/template/gem/.githooks/pre-commit +68 -0
- data/lib/okf/pro/template/gem/.github/workflows/okf-pro.yml +69 -0
- data/lib/okf/pro/template/seed/.claude/settings.json +24 -0
- data/lib/okf/pro/template/seed/.okf/areas/corpus.md +73 -0
- data/lib/okf/pro/template/seed/.okf/areas/index.md +6 -0
- data/lib/okf/pro/template/seed/.okf/board.md +21 -0
- data/lib/okf/pro/template/seed/.okf/glossary/index.md +13 -0
- data/lib/okf/pro/template/seed/.okf/index.md +30 -0
- data/lib/okf/pro/template/seed/.okf/journal/index.md +11 -0
- data/lib/okf/pro/template/seed/.okf/learnings/index.md +13 -0
- data/lib/okf/pro/template/seed/.okf/log.md +10 -0
- data/lib/okf/pro/template/seed/.okf/projects/index.md +23 -0
- data/lib/okf/pro/template/seed/.okf/reference/index.md +16 -0
- data/lib/okf/pro/template/seed/.okf/roadmap.md +33 -0
- data/lib/okf/pro/template/seed/.tmp/.gitkeep +0 -0
- data/lib/okf/pro/template/seed/CLAUDE.md +61 -0
- data/lib/okf/pro/template/seed/README.md +488 -0
- data/lib/okf/pro/template/seed/gitignore +17 -0
- data/lib/okf/pro/version.rb +7 -0
- data/lib/okf/pro/writes.rb +560 -0
- data/lib/okf/pro.rb +198 -0
- metadata +169 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Board anatomy
|
|
2
|
+
|
|
3
|
+
`board.md` is the only cross-work view: the entire commitment surface
|
|
4
|
+
on one bounded page. Sections, in this order:
|
|
5
|
+
|
|
6
|
+
* **In flight** — one *next-action* line per demand. One line, not the
|
|
7
|
+
list: the full outstanding list stays in the project's own
|
|
8
|
+
`index.md`, because a board that carries every step is a project plan
|
|
9
|
+
wearing a board's clothes, and it stops being readable at a glance.
|
|
10
|
+
* **Backlog** — captured, real, and not started. No next action yet;
|
|
11
|
+
writing one is part of promoting it.
|
|
12
|
+
* **Waiting** — who / what / when asked / chase date, the last written
|
|
13
|
+
literally as `chase YYYY-MM-DD`. This is the class
|
|
14
|
+
that rots silently: nothing here fails loudly, it just quietly never
|
|
15
|
+
arrives, and the chase date is the only thing standing between a
|
|
16
|
+
dependency and a month of drift.
|
|
17
|
+
* **Inbox** — dated capture lines — `- YYYY-MM-DD — <the words you
|
|
18
|
+
heard>` — five seconds each, with an optional one-sentence gist. Not a filing
|
|
19
|
+
decision — capture is cheap precisely because it defers filing.
|
|
20
|
+
Conflict lines from Rule 1 (in [SKILL.md](../SKILL.md)) live here too:
|
|
21
|
+
an unsettled contradiction is undifferentiated work until someone
|
|
22
|
+
triages it.
|
|
23
|
+
* **To read** — documents shared with you. Reading *is* the action, and
|
|
24
|
+
only reading takes the line away; a briefing an agent summarised is
|
|
25
|
+
not read, and its line stays.
|
|
26
|
+
* **Deadlines** — dates in the world, one per line, the date first:
|
|
27
|
+
`- YYYY-MM-DD — <what lands>`. They arrive whether or not anyone
|
|
28
|
+
acts, so they sit explicitly outside the pipeline and outside the cap.
|
|
29
|
+
|
|
30
|
+
The dates are grammar, not style, and so is the bullet. Board lines
|
|
31
|
+
start `- ` at column zero — a `*` bullet or an indented dash is a line
|
|
32
|
+
no counter can see, including the cap. The counters read exactly three
|
|
33
|
+
date shapes — a leading `- YYYY-MM-DD` on Inbox and Deadlines lines, a
|
|
34
|
+
literal `chase YYYY-MM-DD` on Waiting lines — and a date in any other
|
|
35
|
+
spelling parses to nothing. Rather than let any of that count as a
|
|
36
|
+
quiet zero (a deadline the 7-day warning cannot see is a deadline that
|
|
37
|
+
lands unclaimed), the audit and the stop gate flag the unreadable line.
|
|
38
|
+
HTML comments are not board content when they keep to their place: a
|
|
39
|
+
comment is `<!-- ... -->` balanced on one line, anywhere on the line,
|
|
40
|
+
and a longer note is a stack of single-line comments. Any `<!--`
|
|
41
|
+
without its `-->` on the same line hides nothing and is flagged —
|
|
42
|
+
comment-intended text must not feed the counters in silence.
|
|
43
|
+
|
|
44
|
+
A section earns its own file only when it stops being bounded (it no
|
|
45
|
+
longer fits on the page) or stops flowing (lines arrive and never
|
|
46
|
+
leave). Until then: one page, atomic edits, and `git log board.md` is
|
|
47
|
+
the state timeline nobody had to maintain.
|
|
48
|
+
|
|
49
|
+
The board is state, not a concept — but OKF exempts only `index.md` and
|
|
50
|
+
`log.md` from the frontmatter rule, so it carries a minimal block with
|
|
51
|
+
`type: Board`. That is the ninth type, and its reason is exactly this:
|
|
52
|
+
the format requires a declaration, and the board is none of the other
|
|
53
|
+
eight. Read the frontmatter as a conformance receipt; the page below it
|
|
54
|
+
is the whole point.
|
|
55
|
+
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Closing a piece of work — four moves, none of them moves a file
|
|
2
|
+
|
|
3
|
+
First, extract the durable part to `learnings/` or `glossary/` — this
|
|
4
|
+
is the moment that habit fires, or the lesson is archived with the work
|
|
5
|
+
and relearned later at full price. Second, mark the project's own
|
|
6
|
+
`index.md` closed on its first line, with the date right after the
|
|
7
|
+
word, separated only by spaces, a colon, a dash (`-`, `–`, `—`),
|
|
8
|
+
asterisks, or an opening parenthesis — these exact forms count:
|
|
9
|
+
`# Title — closed 2026-08-12` · `Closed: 2026-05-01` ·
|
|
10
|
+
`**Closed** 2026-08-12` · `closed (2026-08-12)`. A sentence is not a
|
|
11
|
+
marker ("closed the deal on 2026-08-05", "not closed: 2026-08-12", and
|
|
12
|
+
"we closed, 2026-01-05, the books" all leave the project open), and
|
|
13
|
+
neither is `_closed_` in underscores, which glue to the word.
|
|
14
|
+
<!-- rule: okf-pro-closure-marker -->
|
|
15
|
+
Third, remove its board lines — closure is the one event that takes
|
|
16
|
+
lines away wholesale.
|
|
17
|
+
Fourth, a dated `log.md` entry. The directory stays exactly where it
|
|
18
|
+
is: shared-layer concepts cite into `projects/`, and a move breaks
|
|
19
|
+
every citation to buy a tidiness nobody asked for. Lifecycle is
|
|
20
|
+
metadata; location is filing.
|
|
21
|
+
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Frontmatter policy
|
|
2
|
+
|
|
3
|
+
| Field | Who writes it | When | Meaning |
|
|
4
|
+
|-------|---------------|------|---------|
|
|
5
|
+
| `generated: {by, at}` | An agent | At creation, always | A machine produced this. It has not been checked. |
|
|
6
|
+
| `verified:` (a list) | **The owner's decision** — the agent may hold the pen | Only after actually reading | Who confirmed this, and when. |
|
|
7
|
+
| `stale_after:` | Whoever files the concept | At creation, per the table below | The day this becomes stale — `today >= stale_after`, inclusive. Reports; never gates. |
|
|
8
|
+
| `sources:` | Whoever files the concept | Whenever a claim came from somewhere else | What this was derived from, and the key each claim is attributed through. |
|
|
9
|
+
| `status:` | Whoever settles a collision | On supersession | `draft`, `stable` (the default, so it may be left off), or `deprecated`. |
|
|
10
|
+
|
|
11
|
+
Write concepts with Edit or Write, never with a shell redirect: the
|
|
12
|
+
trust guards read the tool event, and a `Bash` command carries no file
|
|
13
|
+
path and no added text for them to see. A shell command that looks like
|
|
14
|
+
it writes markdown into the bundle is routed to the owner instead, and
|
|
15
|
+
the commit door asks git directly whether a past journal day changed —
|
|
16
|
+
whoever wrote it.
|
|
17
|
+
|
|
18
|
+
Both fields name an **actor**, in one of three forms: `<producer>/<version>`
|
|
19
|
+
for an agent, `human:<id>` for a person, `process:<id>` for an automated
|
|
20
|
+
check. The form is not decoration — the trust tier is read off it. A
|
|
21
|
+
`verified` entry whose `by` is a `human:` actor makes the concept
|
|
22
|
+
**human-reviewed**; entries by anything else make it **machine-confirmed**;
|
|
23
|
+
no `verified` key at all is **unverified**. The To-read line is cleared by
|
|
24
|
+
human review and by nothing else, so a nightly process confirming a briefing
|
|
25
|
+
does not discharge the owner's read.
|
|
26
|
+
|
|
27
|
+
```yaml
|
|
28
|
+
generated: { by: claude/opus-5, at: 2026-08-15T09:12:00Z }
|
|
29
|
+
verified:
|
|
30
|
+
- { by: human:rod, at: 2026-08-15T18:40:00Z }
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Write `verified` as a list, or as one bare `{ by, at }` mapping — those are
|
|
34
|
+
the two shapes the reader accepts. A **scalar** (`verified: human:rod`, or a
|
|
35
|
+
bare date) is not one of them, and it fails in the worst possible direction:
|
|
36
|
+
the guard fires on the word, so the write is routed to you for approval, and
|
|
37
|
+
then the reader drops the malformed value, the tier stays unverified, and the
|
|
38
|
+
To-read line is demanded forever. `okf validate` says so — *verified should be
|
|
39
|
+
a mapping or a list of mappings* — and the gate now surfaces that warning
|
|
40
|
+
rather than discarding it.
|
|
41
|
+
|
|
42
|
+
Concepts an agent authors carry `generated:` from creation. `verified:`
|
|
43
|
+
records **the owner's decision**, made only after actually reading —
|
|
44
|
+
for a briefing, the same event that removes its To-read line. The agent
|
|
45
|
+
may scribe the block, but the hooks turn that write into an explicit
|
|
46
|
+
owner approval, and the approval is the attestation; unattended, with
|
|
47
|
+
nobody to approve, the write is refused. Absent `verified:` on a
|
|
48
|
+
`generated:` concept is not a defect to be tidied away; it is the
|
|
49
|
+
truth.
|
|
50
|
+
|
|
51
|
+
Staleness windows — owned by `/areas/corpus.md`, operative here. To
|
|
52
|
+
change a window: record the decision in `/areas/corpus.md` first, then
|
|
53
|
+
update this table, then a dated `log.md` line — in that order, so the
|
|
54
|
+
bundle's own standard never lags the rule being applied:
|
|
55
|
+
|
|
56
|
+
| Type | `stale_after:` |
|
|
57
|
+
|------|----------------|
|
|
58
|
+
| Briefing | source date + 90d |
|
|
59
|
+
| Term | + 180d |
|
|
60
|
+
| Finding, when it reports measured external figures | + 90d |
|
|
61
|
+
| Learning, Decision, Journal Entry, Transcript, Overview | none |
|
|
62
|
+
|
|
63
|
+
Records don't decay; claims do. A journal entry is true forever — it
|
|
64
|
+
says what happened on a day. A briefing about someone else's pricing is
|
|
65
|
+
a claim about the world, and the world moves.
|
|
66
|
+
|
|
67
|
+
`okf lint .okf --only expired` is what answers *what has gone stale?*,
|
|
68
|
+
and the boundary is the format's rather than this bundle's: a concept
|
|
69
|
+
is stale when the day arrives, inclusive. It reports at `info` and
|
|
70
|
+
never gates — a date passes on the calendar, not on a change, so a gate
|
|
71
|
+
here would fail a morning nobody chose and the only available fix would
|
|
72
|
+
be to falsify a date.
|
|
73
|
+
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# OKF rules
|
|
2
|
+
|
|
3
|
+
* Every `.md` except `index.md` and `log.md` carries YAML frontmatter
|
|
4
|
+
with a non-empty `type`, `title` and `description`.
|
|
5
|
+
* Directory `index.md` files carry **no** frontmatter and list every
|
|
6
|
+
concept in their directory. The root `index.md` carries `okf_version`
|
|
7
|
+
and nothing else — `okf_version: "0.2"`.
|
|
8
|
+
* One concept per file.
|
|
9
|
+
* Links are absolute and bundle-relative: `/reference/thing.md`.
|
|
10
|
+
* After any change: update the directory index and add a dated `log.md`
|
|
11
|
+
entry.
|
|
12
|
+
* **Do not run `okf validate` and `okf lint` after every edit.** The
|
|
13
|
+
gates run themselves — the PostToolUse hook runs both, in process, on
|
|
14
|
+
every Edit and Write, and refuses with what they found. Running them
|
|
15
|
+
by hand afterwards re-reads a bundle that has already been read and
|
|
16
|
+
re-answers a question already answered. Run them when you need the
|
|
17
|
+
*detail behind a refusal*, or when you edited outside the agent's
|
|
18
|
+
tools; otherwise the gate has it.
|
|
19
|
+
* The gates are also runnable by hand when you want the answer before
|
|
20
|
+
the refusal: `okf pro audit .` runs every invariant at once, `okf pro
|
|
21
|
+
state .` says what is on the board, `okf pro unverified .` lists what
|
|
22
|
+
still awaits the owner's read, and `okf pro snapshot .` computes the
|
|
23
|
+
day's line. None of those writes anything.
|
|
24
|
+
* Scratch work goes under `.tmp/` at the repository root, outside the
|
|
25
|
+
bundle entirely.
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# The commit-time door — second of three, between the hooks (agent-time) and
|
|
3
|
+
# CI (push-time). It exists for the edit the other two never see: a change made
|
|
4
|
+
# in your own editor and committed from your own shell.
|
|
5
|
+
#
|
|
6
|
+
# Same contract as .claude/hooks/run: everything it can detect, it refuses
|
|
7
|
+
# loudly. A gate that waves a commit through because its checker is missing has
|
|
8
|
+
# converted "unchecked" into "checked and fine".
|
|
9
|
+
#
|
|
10
|
+
# What gets audited is the STAGED tree, not the worktree. They differ in both
|
|
11
|
+
# directions, and each direction was a hole: stage a broken edit, fix the
|
|
12
|
+
# worktree without re-adding, and a worktree audit passes the broken commit;
|
|
13
|
+
# stage a clean edit next to an unrelated dirty file, and a worktree audit
|
|
14
|
+
# refuses a commit that is fine. The staged tree is what the commit will
|
|
15
|
+
# contain, so it is the only thing worth asking about.
|
|
16
|
+
#
|
|
17
|
+
# One-time setup per clone (hooks do not travel with a checkout):
|
|
18
|
+
# git config core.hooksPath .githooks
|
|
19
|
+
set -u
|
|
20
|
+
|
|
21
|
+
root="$(git rev-parse --show-toplevel)" || exit 1
|
|
22
|
+
|
|
23
|
+
if ! command -v okf > /dev/null 2>&1; then
|
|
24
|
+
echo "COMMIT REFUSED — \`okf\` is not on PATH, so the bundle cannot be audited. Run \`gem install okf okf-pro\`." >&2
|
|
25
|
+
exit 1
|
|
26
|
+
fi
|
|
27
|
+
|
|
28
|
+
# IDENTITY, NOT EXISTENCE — the same proof .claude/hooks/run makes, for the
|
|
29
|
+
# same reason it states: `command -v okf` finds a NAME, and a stray `okf` on
|
|
30
|
+
# PATH that exits 0 is indistinguishable from a clean gate by status alone.
|
|
31
|
+
# Without this, a shim was two silent passes and a commit, at the one door that
|
|
32
|
+
# exists for the edit the agent hooks never see.
|
|
33
|
+
#
|
|
34
|
+
# The handshake runs a real gate through the hook door, because that is where
|
|
35
|
+
# the marker is written and it is written before the check runs — so its
|
|
36
|
+
# presence means okf-pro was actually reached, not merely that something
|
|
37
|
+
# answered to the name. The event is an empty object: it reaches the check,
|
|
38
|
+
# the check has nothing to say about it, and nothing is written anywhere.
|
|
39
|
+
MARKER='okf-pro-enforcer v1'
|
|
40
|
+
if ! printf '{}' | okf pro hook guard-verified 2>&1 > /dev/null | grep -q "^${MARKER}\$"; then
|
|
41
|
+
echo "COMMIT REFUSED — \`okf\` did not identify itself as the enforcer, so nothing was audited. Either okf-pro is not installed (\`gem install okf-pro\`), or something else on PATH answers to \`okf\`." >&2
|
|
42
|
+
exit 1
|
|
43
|
+
fi
|
|
44
|
+
|
|
45
|
+
staged="$(mktemp -d)" || {
|
|
46
|
+
echo "COMMIT REFUSED — could not create a temp directory to materialise the staged tree." >&2
|
|
47
|
+
exit 1
|
|
48
|
+
}
|
|
49
|
+
trap 'rm -rf "$staged"' EXIT
|
|
50
|
+
|
|
51
|
+
# checkout-index writes exactly what the index holds — HEAD plus whatever is
|
|
52
|
+
# staged, minus whatever is not. The trailing slash on --prefix is load-bearing.
|
|
53
|
+
if ! git -C "$root" checkout-index -a --prefix="$staged/" 2> /dev/null; then
|
|
54
|
+
echo "COMMIT REFUSED — could not materialise the staged tree for audit." >&2
|
|
55
|
+
exit 1
|
|
56
|
+
fi
|
|
57
|
+
|
|
58
|
+
# Two questions, and they need different inputs. The append-only record is a
|
|
59
|
+
# question about the CHANGE, so it reads the index directly — materialise the
|
|
60
|
+
# staged tree and the modification is no longer visible as one. It runs first:
|
|
61
|
+
# a rewritten record is not a lint finding, it is the artefact gone.
|
|
62
|
+
#
|
|
63
|
+
# Both verbs answer 0 clean, 1 findings, 2 could-not-run, and this door treats
|
|
64
|
+
# 1 and 2 alike: a commit is refused either way. The distinction is for the
|
|
65
|
+
# reader, and it is why neither verb spells "the checker broke" as 1.
|
|
66
|
+
okf pro records "$root" || exit 1
|
|
67
|
+
|
|
68
|
+
okf pro audit "$staged" || exit 1
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
name: okf-pro
|
|
2
|
+
|
|
3
|
+
# The third door, behind the Claude Code hooks (agent-time) and
|
|
4
|
+
# .githooks/pre-commit (commit-time). Hooks fire only at the agent's tool
|
|
5
|
+
# boundary and git hooks only on machines that configured them, so a push can
|
|
6
|
+
# still carry an edit nothing checked. This is where it gets checked. Nothing is
|
|
7
|
+
# published; the bundle is the artefact.
|
|
8
|
+
|
|
9
|
+
on:
|
|
10
|
+
push:
|
|
11
|
+
pull_request:
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
check:
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v4
|
|
18
|
+
|
|
19
|
+
- uses: ruby/setup-ruby@v1
|
|
20
|
+
with:
|
|
21
|
+
ruby-version: "3.3"
|
|
22
|
+
|
|
23
|
+
- name: Install okf-pro
|
|
24
|
+
run: gem install okf-pro
|
|
25
|
+
|
|
26
|
+
# The CLI is asked directly, and on purpose, even though `okf pro audit`
|
|
27
|
+
# runs the same two analyzers. A checker that is the only thing verifying
|
|
28
|
+
# the bundle can be wrong in the one direction nobody notices — always
|
|
29
|
+
# passing — and then CI is decorative in a way no test would catch. These
|
|
30
|
+
# two steps are the independent authority; audit below adds what only the
|
|
31
|
+
# checker knows.
|
|
32
|
+
- name: Validate — OKF conformance
|
|
33
|
+
run: okf validate .okf
|
|
34
|
+
|
|
35
|
+
# `okf lint` exits 0 even when it finds problems. Without --fail-on warn
|
|
36
|
+
# this step is decorative: green forever, and green for reasons unrelated
|
|
37
|
+
# to the bundle being any good.
|
|
38
|
+
- name: Lint — curation quality
|
|
39
|
+
run: okf lint .okf --fail-on warn
|
|
40
|
+
|
|
41
|
+
# The invariants that are not conformance: a snapshot under the log's
|
|
42
|
+
# newest day, every open project paired to a board line, every unverified
|
|
43
|
+
# briefing still owed a read. These are the ones an editor-made commit
|
|
44
|
+
# bypasses entirely, and they are the reason this door exists.
|
|
45
|
+
- name: Audit — the bundle's own invariants
|
|
46
|
+
run: okf pro audit .
|
|
47
|
+
|
|
48
|
+
# Attestation reports; it does not gate. "Unverified" is the truth about a
|
|
49
|
+
# concept, not a defect in it, and a gate here would pressure toward the
|
|
50
|
+
# one lie the whole system guards against — so it lands in the run summary,
|
|
51
|
+
# where a person reads it while deciding what to look at.
|
|
52
|
+
#
|
|
53
|
+
# Staleness is asked of `okf lint` rather than of this gem: `stale_after`
|
|
54
|
+
# is the format's own field (§5.5), the kernel owns where its boundary
|
|
55
|
+
# falls, and a second implementation of "is this past its window" that
|
|
56
|
+
# disagreed by a day would be worse than none.
|
|
57
|
+
- name: Attestation and staleness — report only
|
|
58
|
+
if: always()
|
|
59
|
+
run: |
|
|
60
|
+
{
|
|
61
|
+
echo "## Attestation and staleness"
|
|
62
|
+
echo
|
|
63
|
+
echo "Advisory. Unverified is the truth, not a defect; a passed window is a prompt to look."
|
|
64
|
+
echo
|
|
65
|
+
echo '```'
|
|
66
|
+
okf pro unverified .
|
|
67
|
+
okf lint .okf --only expired || true
|
|
68
|
+
echo '```'
|
|
69
|
+
} >> "$GITHUB_STEP_SUMMARY"
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"hooks": {
|
|
3
|
+
"PreToolUse": [
|
|
4
|
+
{ "matcher": "Edit|Write|MultiEdit",
|
|
5
|
+
"hooks": [
|
|
6
|
+
{ "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/run guard-verified" },
|
|
7
|
+
{ "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/run journal-guard" } ] },
|
|
8
|
+
{ "matcher": "Bash",
|
|
9
|
+
"hooks": [
|
|
10
|
+
{ "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/run shell-guard" } ] }
|
|
11
|
+
],
|
|
12
|
+
"PostToolUse": [
|
|
13
|
+
{ "matcher": "Edit|Write|MultiEdit",
|
|
14
|
+
"hooks": [
|
|
15
|
+
{ "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/run post-edit" } ] }
|
|
16
|
+
],
|
|
17
|
+
"Stop": [
|
|
18
|
+
{ "hooks": [ { "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/run stop-gate" } ] }
|
|
19
|
+
],
|
|
20
|
+
"SessionStart": [
|
|
21
|
+
{ "hooks": [ { "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/run session-context" } ] }
|
|
22
|
+
]
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Overview
|
|
3
|
+
title: Corpus
|
|
4
|
+
description: The standard this knowledge base is kept at — the naming policy, ownership of the staleness windows, and the limit reconciliation runs against.
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# The standard
|
|
8
|
+
|
|
9
|
+
Every adopter has exactly one area on day one: tending the thing they are
|
|
10
|
+
reading right now. It has no done. It has a level, and the level is this — **a
|
|
11
|
+
claim in here can be found by someone who does not already know it is here,
|
|
12
|
+
and does not sit next to its own contradiction.**
|
|
13
|
+
|
|
14
|
+
This file holds the standard, never the state. Counts live in
|
|
15
|
+
[log.md](/log.md); open work lives on [board.md](/board.md). If you find
|
|
16
|
+
yourself updating this file daily, something that belongs on the board has
|
|
17
|
+
leaked into it.
|
|
18
|
+
|
|
19
|
+
# Reconciliation
|
|
20
|
+
|
|
21
|
+
The discipline itself is operative as Rule 1 of the okf-pro skill, which
|
|
22
|
+
every bundle-touching session loads: search before filing, read bodies rather
|
|
23
|
+
than titles, deprecate the loser at ingestion, and send what cannot be settled
|
|
24
|
+
to [board.md](/board.md) as one dated conflict line.
|
|
25
|
+
|
|
26
|
+
One operative copy, and it is not this one — this area holds the standard that
|
|
27
|
+
rule serves, and the rule's limit: it catches collisions as well as the search
|
|
28
|
+
vocabulary does, and no better. That limit is what makes the next section
|
|
29
|
+
load-bearing rather than cosmetic.
|
|
30
|
+
|
|
31
|
+
# Naming policy
|
|
32
|
+
|
|
33
|
+
* **Never name a concept, tag, or type after something that already means
|
|
34
|
+
three things in your domain.** A file called `status.md` in a bundle where
|
|
35
|
+
"status" is a ticket field, a deploy state, and a weekly email is a file
|
|
36
|
+
nobody can search for.
|
|
37
|
+
* Prefer the phrase you would actually say out loud to a colleague. The search
|
|
38
|
+
that matters is the one made by someone who has forgotten the filing.
|
|
39
|
+
* Types are a small vocabulary, added to reluctantly: Briefing, Decision,
|
|
40
|
+
Finding, Learning, Term, Journal Entry, Transcript, Overview, Board. A tenth
|
|
41
|
+
type needs a reason that survives being said aloud.
|
|
42
|
+
* [glossary/](/glossary/) is where a contested word goes to get one meaning.
|
|
43
|
+
When two concepts disagree because they are using a word differently, the
|
|
44
|
+
fix is usually a Term, not an argument.
|
|
45
|
+
* **A directory is a retrieval question, and a room pays rent by answering one
|
|
46
|
+
no other room answers.** The five here are the starting set rather than the
|
|
47
|
+
closed set — but a sixth is earned by an incident, never anticipated. What is
|
|
48
|
+
forbidden is the *catch-all*: a room meaning "everything else" is a blind spot
|
|
49
|
+
by construction, because things enter it and nothing enumerates them again,
|
|
50
|
+
and nobody has ever searched for the thing that did not fit. That is also why
|
|
51
|
+
this bundle splits what PARA keeps as one Resources room into
|
|
52
|
+
[reference/](/reference/), [learnings/](/learnings/) and
|
|
53
|
+
[glossary/](/glossary/): three questions, asked at three different moments.
|
|
54
|
+
|
|
55
|
+
# Staleness
|
|
56
|
+
|
|
57
|
+
This area **owns** the staleness table — deciding what decays, and how fast.
|
|
58
|
+
The table itself lives in the okf-pro skill
|
|
59
|
+
(`.claude/skills/okf-pro/SKILL.md`), next to the frontmatter policy it
|
|
60
|
+
governs, because one operative copy beats two agreeing copies until the day
|
|
61
|
+
they stop agreeing.
|
|
62
|
+
|
|
63
|
+
Ownership means: when a window proves wrong in use — briefings going stale
|
|
64
|
+
while still accurate, terms rotting before their date — the number changes
|
|
65
|
+
here first as a decision, then in the skill as the rule, and the change gets a
|
|
66
|
+
[log.md](/log.md) line.
|
|
67
|
+
|
|
68
|
+
`stale_after:` reports; it never gates. A date that has passed is a prompt to
|
|
69
|
+
look, not a verdict that the concept is wrong. Where the boundary falls is the
|
|
70
|
+
format's to say and not this bundle's: a concept is stale when the day has
|
|
71
|
+
arrived, inclusive, and `okf lint --only expired` is what answers the
|
|
72
|
+
question. A second implementation of it that disagreed by a day would be worse
|
|
73
|
+
than none.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Board
|
|
3
|
+
title: Board
|
|
4
|
+
description: The single page of forward state — every commitment, in six sections, on one page you can read at a glance.
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Board
|
|
8
|
+
|
|
9
|
+
**In flight: 0/5** · updated never
|
|
10
|
+
|
|
11
|
+
## In flight
|
|
12
|
+
|
|
13
|
+
## Backlog
|
|
14
|
+
|
|
15
|
+
## Waiting
|
|
16
|
+
|
|
17
|
+
## Inbox
|
|
18
|
+
|
|
19
|
+
## To read
|
|
20
|
+
|
|
21
|
+
## Deadlines
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Glossary
|
|
2
|
+
|
|
3
|
+
Terms that need one fixed meaning here, because they mean three things
|
|
4
|
+
elsewhere.
|
|
5
|
+
|
|
6
|
+
A term earns a file when two concepts disagree and the disagreement turns out
|
|
7
|
+
to be about a word. The fix is usually a Term, not an argument.
|
|
8
|
+
|
|
9
|
+
Naming is governed by the policy in [areas/corpus.md](/areas/corpus.md): never
|
|
10
|
+
mint a name that already means something else in your own domain, and prefer
|
|
11
|
+
the phrase you would actually say out loud to a colleague.
|
|
12
|
+
|
|
13
|
+
Nothing defined yet.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
okf_version: "0.2"
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Second Brain
|
|
6
|
+
|
|
7
|
+
A personal knowledge bundle. Three zones: what I know, what I am doing, what
|
|
8
|
+
time is doing to both.
|
|
9
|
+
|
|
10
|
+
The rules that govern writing into it live in the okf-pro skill
|
|
11
|
+
(`.claude/skills/okf-pro/SKILL.md`), outside this bundle, because the agent
|
|
12
|
+
loads it from there and because instructions are not knowledge. `CLAUDE.md`
|
|
13
|
+
sits outside for the same reason.
|
|
14
|
+
|
|
15
|
+
# KNOW
|
|
16
|
+
|
|
17
|
+
* [reference/](/reference/) - what other people produced, summarised and attributed.
|
|
18
|
+
* [learnings/](/learnings/) - conclusions of mine that outlive the work that produced them.
|
|
19
|
+
* [glossary/](/glossary/) - terms that need one fixed meaning.
|
|
20
|
+
|
|
21
|
+
# ACT
|
|
22
|
+
|
|
23
|
+
* [projects/](/projects/) - work with a definition of done.
|
|
24
|
+
* [areas/](/areas/) - standards held indefinitely, with no done.
|
|
25
|
+
|
|
26
|
+
# TIME
|
|
27
|
+
|
|
28
|
+
* [board.md](/board.md) - the single page of forward state.
|
|
29
|
+
* [journal/](/journal/) - the backward record, one entry per day.
|
|
30
|
+
* [roadmap.md](/roadmap.md) - the quarterly wavelength.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Journal
|
|
2
|
+
|
|
3
|
+
One entry per day, named `YYYY-MM-DD.md`. The backward record: what happened,
|
|
4
|
+
what it meant, what was decided.
|
|
5
|
+
|
|
6
|
+
Entries are append-only — a past day is a record, not a draft — and the commit
|
|
7
|
+
door asks git directly whether a past day changed. Corrections go in today's
|
|
8
|
+
entry, pointing back at the day they correct.
|
|
9
|
+
|
|
10
|
+
Nothing recorded yet. The first entry is the first day this bundle is used,
|
|
11
|
+
dated by you, not by the template.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Learnings
|
|
2
|
+
|
|
3
|
+
Conclusions of mine that are true beyond the work that produced them.
|
|
4
|
+
|
|
5
|
+
The test for filing here rather than in a project: *does it outlive the piece
|
|
6
|
+
of work that produced it?* A finding that only makes sense inside one project
|
|
7
|
+
belongs under `projects/`; a lesson that would still be worth knowing after
|
|
8
|
+
that project is forgotten belongs here.
|
|
9
|
+
|
|
10
|
+
This is also where closing a piece of work sends its durable part — extracted
|
|
11
|
+
at closure, or archived with the work and relearned later at full price.
|
|
12
|
+
|
|
13
|
+
Nothing concluded yet.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Update Log
|
|
2
|
+
|
|
3
|
+
What changed in this bundle, newest day first. One `## YYYY-MM-DD` heading per
|
|
4
|
+
day, and under it the day's lines — including the mechanical `**Snapshot**`
|
|
5
|
+
line the end-of-day sitting appends.
|
|
6
|
+
|
|
7
|
+
Nothing logged yet. The first heading is written on the first day this bundle
|
|
8
|
+
is used, dated by you: a template that shipped with a date would hand you
|
|
9
|
+
somebody else's calendar, and the dormancy window measures this bundle's age
|
|
10
|
+
by its oldest journal entry.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Projects
|
|
2
|
+
|
|
3
|
+
Work with a definition of done. Each project is a directory with its own
|
|
4
|
+
`index.md`; concepts scoped to that work live beside it.
|
|
5
|
+
|
|
6
|
+
A project is closed by marking its own `index.md` on the first line — the word
|
|
7
|
+
`closed`, then the date, separated only by spaces, a colon, a dash, asterisks
|
|
8
|
+
or an opening parenthesis. These forms count:
|
|
9
|
+
|
|
10
|
+
* `# Title — closed 2026-08-12`
|
|
11
|
+
* `Closed: 2026-05-01`
|
|
12
|
+
* `**Closed** 2026-08-12`
|
|
13
|
+
* `closed (2026-08-12)`
|
|
14
|
+
|
|
15
|
+
A sentence that merely mentions the word is not a marker, and neither is
|
|
16
|
+
`_closed_` in underscores — the okf-pro skill's closing ritual enumerates
|
|
17
|
+
what does and does not count, and it is the only place that list lives.
|
|
18
|
+
|
|
19
|
+
The directory then stays exactly where it is —
|
|
20
|
+
concepts elsewhere cite into it, and a move breaks every citation to buy a
|
|
21
|
+
tidiness nobody asked for. Lifecycle is metadata; location is filing.
|
|
22
|
+
|
|
23
|
+
Nothing started yet.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Reference
|
|
2
|
+
|
|
3
|
+
What other people produced: their document, their claim, your summary of it,
|
|
4
|
+
with the source recorded.
|
|
5
|
+
|
|
6
|
+
Everything here carries `sources:` — what it was derived from — and attributes
|
|
7
|
+
individual claims with footnotes keyed to a `sources[].id`. That is the whole
|
|
8
|
+
argument of this directory: a claim in here can be traced back to whatever it
|
|
9
|
+
came from.
|
|
10
|
+
|
|
11
|
+
A concept an agent wrote carries `generated:` from creation, and stays
|
|
12
|
+
**unverified** until you have actually read it. That is the truth about it,
|
|
13
|
+
not a defect in it, and the To-read line on [board.md](/board.md) stays until
|
|
14
|
+
the reading happens.
|
|
15
|
+
|
|
16
|
+
Nothing filed yet.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Overview
|
|
3
|
+
title: Roadmap
|
|
4
|
+
description: The quarterly wavelength — intent stated sparsely, linking out to the work that carries it.
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# What belongs here
|
|
8
|
+
|
|
9
|
+
The quarter's intent, in a handful of lines. Not a plan, not a backlog, not a
|
|
10
|
+
second board — those exist and they are elsewhere. This file answers one
|
|
11
|
+
question: *if the next three months went well, what would be different?*
|
|
12
|
+
Write it sparsely and link out; a roadmap that restates [board.md](/board.md)
|
|
13
|
+
has become the second copy, and the second copy rots. The rule that keeps the
|
|
14
|
+
two apart is the routing question in the okf-pro skill: the board holds
|
|
15
|
+
commitments, this file holds intent, and intent that has become a commitment
|
|
16
|
+
belongs on the board.
|
|
17
|
+
|
|
18
|
+
# This quarter
|
|
19
|
+
|
|
20
|
+
* No intent stated yet. Write one line when a quarter's shape is actually
|
|
21
|
+
known — a blank quarter is more honest than an invented one.
|
|
22
|
+
|
|
23
|
+
# The standing accusation
|
|
24
|
+
|
|
25
|
+
This file is the least field-proven element of the design. The board and the
|
|
26
|
+
journal earn their keep every day; the roadmap claims a wavelength nobody has
|
|
27
|
+
yet proved a personal system needs. If a month of use never touches it, it
|
|
28
|
+
stands accused — delete it, remove its line from [index.md](/index.md), and
|
|
29
|
+
note the deletion in [log.md](/log.md). All three, or the index links at
|
|
30
|
+
nothing and lint says so.
|
|
31
|
+
|
|
32
|
+
It is the one file in the core the design lets you remove. Everything else
|
|
33
|
+
here the gates require, because without it they disengage in silence.
|
|
File without changes
|