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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions docs/now/2026-09-09-the-27-agent-alphabet-as-t27-specs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# NOW -- The 27-agent alphabet as first-class .t27 specs (2026-09-09)

## The 27-agent alphabet as first-class .t27 specs (Closes #3545)

- `specs/agents/` (27): one `.t27` module per letter of `docs/agents/AGENTS_ALPHABET.md` -- A..Z and the 27th, Ti (`ti.t27`, `LETTER = "TI"`, `ENABLED = false`, register R26 as the site's alphabet table gives it). Every constant is `pub const`; the schema is in `specs/agents/README.md`. Layer four of the ladder Specs -> Skills -> Crons -> Agents: the alphabet table, `docs/agents/AGENTS.md` and `.claude/agents/*.md` were prose; the spec now states the letter (LETTER, ORDINAL, LETTER_NAME, NAME, DOMAIN, ARCHETYPE, REGISTER, LAYER, ENTRY/EXIT_INVARIANT, CLARA_ROLE), the documents that bind it (`SOUL = "SOUL.md"`, `AGENTS_DOC = "AGENTS.md"`, `ALPHABET = "docs/agents/AGENTS_ALPHABET.md"`), its KEY_FILES and its EXPERIENCE_LOG. Transcribed from the alphabet's FULL TABLE and per-agent schema sections; nothing invented.
- Skill binding is evidence-gated. A letter holds a skill (`SKILLS`) only when a source evidently binds it: today **T** alone, via `.claude/agents/trinity.md` (phi-loop, tri-pipeline). The other 26 carry `SKILLS = []` and a `SKILLS_NOTE` saying which sources were checked. `specs/OWNERS.md` rows are catalog ownership, not held skills, and are not read as bindings. `TOOLS`/`TOOLS_NOTE` are optional fields reserved for layer five (tri CLI, MCP) and are absent here.
- The site (gHashTag/trinity#976) vendors a byte-identical copy under `apps/website/public/t27/files/specs/agents/` and generates `public/agents/spec-agents.json` from it through the compiler wasm at build time -- no regex over `.t27`. An unknown `SKILLS` id fails the build; crons are derived as the jobs whose `RUNS` name one of the letter's skills (none today: every cron `RUNS` is `[]`). Measured: **27/27** typecheck ok under the vendored wasm (sha256 `4d9c0447b5ca2887...`), nothing discarded; the same caveat as for skills holds -- `typecheck.ok` is lenient, the generator's field schema is the gate.
- Experience is joined, not assumed. The site reads `.trinity/experience/**` from both checkouts (trinity: 440 files, 383 episodes, 56 unreadable; t27: 2 files, 3 episodes) with an explicit attribution rule (which JSON fields, which letters). Result on this snapshot: **386 episodes, 0 attributed** -- no episode carries an agent letter (`agent` is absent in 385, `claude-opus-4.6` in 1). Every agent card therefore reads "no attributed episodes"; the unattributed count is shown and assigned to nobody. The specs' witness is `spec-only` for all 27 until a log names a letter.
- Language: the specs are English-only (LANG-EN). RU summaries travel through the existing contract: `specs/i18n/agents-ru.t27` `SCOPE` gains `specs/agents` (`[3]str`), and the bundle `trinity:apps/website/i18n/agents.ru.json` gains 27 entries keyed by `ID` (`t27/A` .. `t27/Z`, `t27/TI`). Coverage measured on the site: ru 27/27 agents, 0 orphans.
- Inconsistencies found in the sources are recorded in the README rather than resolved: Ti is r20 / TAW in one place and R19 is Tau's register; F and U both claim phi; `specs/OWNERS.md` says R-Reasoning where the alphabet says R = Runtime.
- Not claimed: no agent is launched by a spec; no register renamed; no episode attributed; `gate-topology` and `untrusted-input` still fail on `master` for already-merged PRs and are not addressed here.
- `specs/OWNERS.md` gains the row `agents/` -> **T-Queen**.
1 change: 1 addition & 0 deletions specs/OWNERS.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
| `demos/`, `sandbox/` | **A-Architect** / **Q-QA** | Examples; not ring gold by default |
| `isa/` | **C-Compiler** | Register alphabet |
| `skills/`, `crons/`, `i18n/` | **T-Queen** | Agent skills and scheduled jobs as `.t27` specs, plus the per-locale translation contracts (`i18n/agents-<locale>.t27`) that point at the site's text bundles; the site (gHashTag/trinity) generates its catalogs from a vendored copy |
| `agents/` | **T-Queen** | The 27 agents of `docs/agents/AGENTS_ALPHABET.md` as `.t27` specs (`agents/<letter>.t27`, `KIND = "agent"`): letter, domain, archetype, register, invariants, the documents that bind it (`SOUL.md`, `AGENTS.md`, the alphabet) and the skills a source evidently binds; the site joins experience by LETTER |

Each subtree with substantial churn should keep a local **`OWNERS.md`** (see below).

Expand Down
138 changes: 138 additions & 0 deletions specs/agents/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
# specs/agents — the 27-agent alphabet as first-class `.t27` specs

> **Where this lives.** This directory in `gHashTag/t27` is the canonical home of these
> specs — edit them here. `gHashTag/trinity` keeps a vendored copy under
> `apps/website/public/t27/files/specs/agents/` and its build reads that copy through the
> vendored compiler wasm (`t27_compiler.wasm`). The wasm's `typecheck.ok` is necessary,
> not sufficient, so the site's generator (`scripts/agents-from-specs.mjs`) also checks the
> field schema below. The bootstrap compiler on `master` was not run against these files in
> the commit that added them.


One file per agent of the Trinity alphabet (`docs/agents/AGENTS_ALPHABET.md`, v3.0): A…Z and
the 27th seat, Ti. The `.t27` file is the source of truth for the agent card on t27.ai;
the JSON the site serves (`public/agents/spec-agents.json`) is generated from these files by
the real compiler (`t27_compiler.wasm`), never by a regex. The agents are bound together by
`SOUL.md` and `AGENTS.md` at the repository root and by their experience log
(`.trinity/experience/`), which is joined to the cards by evidence only (see below).

File name: `<letter>.t27` (lower-case; `ti.t27` for the 27th); module name: `agent_<letter>`.
Specs are English-only and ASCII-only (t27 LANG-EN / L3 PURITY): the Greek glyph of a letter
is carried as its name in `LETTER_NAME`, not as a character.

## The ladder

```
Specs -> Skills -> Crons -> Agents
specs/** specs/skills specs/crons specs/agents
what is what a run what starts who holds the skills, under which
declared does a run and law (SOUL.md, AGENTS.md), with which
when entry/exit invariant, and what they
have lived through (experience)
```

Each layer is declared in `.t27`, vendored byte-identically into `gHashTag/trinity`
(`apps/website/public/t27/files/specs/...`), compiled by the vendored wasm at build time and
rendered by one explorer per layer (`#/skills`, `#/crons`, `#/agents`). Links go downward
only through declared fields: an agent names its `SKILLS`; a cron names the skills it `RUNS`;
so an agent's crons are *derived* (crons whose `RUNS` intersect the agent's `SKILLS`), never
written by hand.

## Schema (every constant is `pub const`)

| constant | type | meaning |
|-------------------|-----------|-------------------------------------------------------------------------------------------|
| `KIND` | `str` | always `"agent"` |
| `ID` | `str` | `t27/<LETTER>` (`t27/A` … `t27/Z`, `t27/TI`) |
| `LETTER` | `str` | `A`…`Z` or `TI` |
| `ORDINAL` | `u8` | 1…27, the row in the alphabet table |
| `LETTER_NAME` | `str` | the Greek/Hebrew letter name from the table (`Alpha`, `Phi`, `Double-Vav`, `Ti`) |
| `NAME` | `str` | display name as in the table, e.g. `Epsilon (Experience)` |
| `DOMAIN` | `str` | the Domain column |
| `ARCHETYPE` | `str` | the Archetype column (`Bull - leader, primary force`) |
| `REGISTER` | `str` | `R0`…`R26` from the table |
| `LAYER` | `str` | `Archetypal` (A–I), `Spiritual` (J–R) or `Physical` (S–Z, Ti) — the three-layer tables |
| `SUMMARY_EN` | `str` | one paragraph: `<DOMAIN>. <Trinity-meaning sentence>` |
| `SOUL` | `str` | `SOUL.md` — the law every agent is bound by |
| `AGENTS_DOC` | `str` | `AGENTS.md` — the operational rules |
| `ALPHABET` | `str` | `docs/agents/AGENTS_ALPHABET.md` — where the roster is defined |
| `KEY_FILES` | `[N]str` | the Key files column; `[0]str = []` for the reserved seat |
| `ENTRY_INVARIANT` | `str` | the Entry invariant of the schema-details section |
| `EXIT_INVARIANT` | `str` | the Exit invariant |
| `CLARA_ROLE` | `str` | the CLARA role; `""` when the table says `—` |
| `SKILLS` | `[N]str` | skill IDs (`specs/skills`) the agent holds — ONLY when a source binds them (see below) |
| `SKILLS_NOTE` | `str` | where the binding comes from, or why `SKILLS` is empty; required when `SKILLS` is `[]` |
| `TOOLS` | `[N]str` | *optional, layer 5:* tool IDs (`specs/tools`) the agent owns, evidence-bound like SKILLS |
| `TOOLS_NOTE` | `str` | *optional:* source of the tool binding; required when `TOOLS` is present and `[]` |
| `EXPERIENCE_LOG` | `str` | the experience directory the agent's episodes are read from, or `""` |
| `ENABLED` | `bool` | `false` only for the reserved seat (Ti) |

The generator (`scripts/agents-from-specs.mjs` in trinity) fails the build when: the compiler
verdict is not clean; a constant is missing, not `pub`, or has the wrong annotation / array
length / integer range; `ID` ≠ `t27/<LETTER>`; the file name does not match the letter;
`ORDINAL` is duplicated or outside 1…27; `LAYER` is not one of the three; `SKILLS` names an
ID with no skill spec; `SKILLS` is empty without a `SKILLS_NOTE`; or the directory does not
hold exactly 27 specs. The wasm's `typecheck.ok` alone is necessary, not sufficient.

## Skill binding rule (evidence, not inference)

`SKILLS` is filled only when one of these names the skill for that letter:

1. a row of `specs/OWNERS.md` that assigns a skill directory to the letter;
2. the agent's prompt file `.claude/agents/<name>.md` referencing a skill directory or
`/skill` command;
3. the alphabet's Key files column pointing at a skill directory.

At the commit these specs were written from, only one binding exists:
`.claude/agents/trinity.md` (the T / Queen prompt) runs `/phi-loop` (L33) and
`/tri-pipeline` (L45), so `T` holds `t27/phi-loop` and `t27/tri-pipeline`. Every other
agent has `SKILLS = []` with a `SKILLS_NOTE` saying so. Nothing is inferred from a domain
name matching a skill name.

## Experience attribution rule (`public/agents/experience.json`)

`scripts/sync-agents-experience.mjs` (trinity) reads `.trinity/experience/**` in the trinity
checkout and in the t27 checkout (`T27_ROOT`; when unset, the sibling directory `../t27` of the
trinity repo root, i.e. `$(git rev-parse --show-toplevel)/../t27`) and writes a committed
snapshot. No absolute home path is written anywhere. The rule,
kept identical in the script header:

1. An episode is one JSON object: a `*.json` file holding an object, each object of a `*.json`
array, or each line of a `*.jsonl` file. `*.md` files are listed as notes, not counted.
Files that do not parse are counted as `unreadable` and listed.
2. The agent is read from the first present field of `agent_letter`, `letter`, `agent`,
`agent_id`, `agents` (array: every member), `owner`.
3. A value attributes to a letter only when, case-insensitively, it is one letter A–Z; or
`ti` / `27th`; or `t27/<letter>`; or it starts with `agent-<letter>` / `agent_<letter>` /
`agent <letter>` followed by a non-letter. A model name (`claude-opus-4.6`), a person or a
repository is **not** a letter: the episode is counted under `unattributed` and the raw
value is tallied in `unattributed.agentValues`.
4. Timestamp from `timestamp` (unix s / ms / ISO-8601) else `date`; outcome from `verdict`,
`status`, `outcome`, or `success`; lessons from `learnings`, `lessons`, `lessons_learned`,
then `mistakes` (prefixed `mistake:`), 160 characters each, at most 12 per agent.
5. Output is sorted so two runs over the same trees differ only in `generatedAt`.

The generator joins the snapshot by `LETTER`. An agent with zero attributed episodes is shown
as "no attributed episodes" and carries the witness label `spec-only`; one with episodes is
`spec+experience`. At the time of writing, no episode in either repository names an agent
letter (trinity episodes have no agent field; the t27 ring file names a model), so all 27
agents are `spec-only` and the whole log (386 episodes, 56 unreadable files) is
`unattributed`. That is the measured state, not a gap to paper over.

## Known inconsistencies in the source document (carried as written, not corrected)

* The full table gives Ti the register `r20 / TAW`; the detail section gives `υ / R19`.
The specs use `R26` for the 27th seat as the only free register; the table row is quoted in
the alphabet document, not here.
* `F` and `U` are both glyphed `φ` in the table; `LETTER_NAME` keeps `Phi` for F and `Upsilon`
for U from the detail sections.
* `specs/OWNERS.md` names `R-Reasoning`; the alphabet has `R = Rho (Runtime)`. The specs follow
the alphabet (the roster's source of truth); the OWNERS row is unchanged.

## Editing

Edit in `gHashTag/t27` (`specs/agents/<letter>.t27`), re-vendor the byte-identical copy into
`gHashTag/trinity` `apps/website/public/t27/files/specs/agents/`, then run
`node scripts/agents-from-specs.mjs` and `npm run check:agents` in `apps/website`. Russian
summaries live in the bundle declared by `specs/i18n/agents-ru.t27`
(`apps/website/i18n/agents.ru.json`, entries keyed `t27/<LETTER>`); the spec stays English.
42 changes: 42 additions & 0 deletions specs/agents/a.t27
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// SPDX-License-Identifier: Apache-2.0
; specs/agents/a.t27 -- agent t27/A, letter A of the 27-agent alphabet
; Source of truth for the agent card on t27.ai (#/agents?agent=t27/A).
; Transcribed from docs/agents/AGENTS_ALPHABET.md (v3.0): the FULL TABLE row and the
; "Agent A - Alpha (Architecture)" schema section. The agent is bound to the others by SOUL.md,
; AGENTS.md and the experience log; the JSON the site serves is generated from this
; file by the real compiler, nothing below is parsed with a regex. ASCII only (L3).
; phi^2 + 1/phi^2 = 3 | TRINITY

module agent_a;

pub const KIND : str = "agent";
pub const ID : str = "t27/A";
pub const LETTER : str = "A";
; position in the alphabet, 1..27 (the 27th letter is Ti, register R26)
pub const ORDINAL : u8 = 1;
pub const LETTER_NAME : str = "Alpha";
pub const NAME : str = "Alpha (Architecture)";
pub const DOMAIN : str = "Architecture / ADR / SOUL";
pub const ARCHETYPE : str = "Bull - leader, primary force";
; Coptic register from the schema section (the ISA register the agent is bound to)
pub const REGISTER : str = "R0";
; alphabet layer: Archetypal (A-I), Spiritual (J-R), Physical (S-27th)
pub const LAYER : str = "Archetypal";
pub const SUMMARY_EN : str = "Architecture / ADR / SOUL. SOUL.md is the primary cause and the ADRs are the constitution of the system.";
; The three documents that bind every agent, as repo-root paths in gHashTag/t27.
pub const SOUL : str = "SOUL.md";
pub const AGENTS_DOC : str = "AGENTS.md";
pub const ALPHABET : str = "docs/agents/AGENTS_ALPHABET.md";
; Key files as the alphabet lists them (paths and globs relative to the t27 root).
pub const KEY_FILES : [3]str = ["SOUL.md", "architecture/ADR-*.md", "architecture/CANON_DE_ZIGFICATION.md"];
pub const ENTRY_INVARIANT : str = "SOUL.md exists, is ASCII-only, and defines L1-L7 laws";
pub const EXIT_INVARIANT : str = "All ADRs reviewed, consistent with constitution, no conflicts";
; CLARA role from the alphabet (TA1/TA2 work areas).
pub const CLARA_ROLE : str = "TA1: AR Architecture Design - designs AR module architecture, ensures composability";
; Skill IDs the agent holds. Bound only where a source names the skill; SKILLS_NOTE
; cites that source or says why the list is empty.
pub const SKILLS : [0]str = [];
pub const SKILLS_NOTE : str = "No source binds a skill to this agent: the alphabet key files point at specs and docs, not at a skill directory, no .claude/agents file names one, and specs/OWNERS.md has no row for it.";
; Where the agent logs episodes (AGENTS_ALPHABET.md: "Logs to .trinity/experience/").
pub const EXPERIENCE_LOG : str = ".trinity/experience/";
pub const ENABLED : bool = true;
42 changes: 42 additions & 0 deletions specs/agents/b.t27
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// SPDX-License-Identifier: Apache-2.0
; specs/agents/b.t27 -- agent t27/B, letter B of the 27-agent alphabet
; Source of truth for the agent card on t27.ai (#/agents?agent=t27/B).
; Transcribed from docs/agents/AGENTS_ALPHABET.md (v3.0): the FULL TABLE row and the
; "Agent B - Beta (Build)" schema section. The agent is bound to the others by SOUL.md,
; AGENTS.md and the experience log; the JSON the site serves is generated from this
; file by the real compiler, nothing below is parsed with a regex. ASCII only (L3).
; phi^2 + 1/phi^2 = 3 | TRINITY

module agent_b;

pub const KIND : str = "agent";
pub const ID : str = "t27/B";
pub const LETTER : str = "B";
; position in the alphabet, 1..27 (the 27th letter is Ti, register R26)
pub const ORDINAL : u8 = 2;
pub const LETTER_NAME : str = "Beta";
pub const NAME : str = "Beta (Build)";
pub const DOMAIN : str = "Build / Pipeline";
pub const ARCHETYPE : str = "House - container, dwelling";
; Coptic register from the schema section (the ISA register the agent is bound to)
pub const REGISTER : str = "R1";
; alphabet layer: Archetypal (A-I), Spiritual (J-R), Physical (S-27th)
pub const LAYER : str = "Archetypal";
pub const SUMMARY_EN : str = "Build / Pipeline. build.tri is the house of specifications and the pipeline is its dwelling.";
; The three documents that bind every agent, as repo-root paths in gHashTag/t27.
pub const SOUL : str = "SOUL.md";
pub const AGENTS_DOC : str = "AGENTS.md";
pub const ALPHABET : str = "docs/agents/AGENTS_ALPHABET.md";
; Key files as the alphabet lists them (paths and globs relative to the t27 root).
pub const KEY_FILES : [2]str = ["build.tri", "src/tri/pipeline/"];
pub const ENTRY_INVARIANT : str = "Build system is clean, no stale artifacts";
pub const EXIT_INVARIANT : str = "All tests pass, CI pipeline is green";
; The alphabet lists no CLARA role for this agent ("-").
pub const CLARA_ROLE : str = "";
; Skill IDs the agent holds. Bound only where a source names the skill; SKILLS_NOTE
; cites that source or says why the list is empty.
pub const SKILLS : [0]str = [];
pub const SKILLS_NOTE : str = "No source binds a skill to this agent: the alphabet key files point at specs and docs, not at a skill directory, no .claude/agents file names one, and specs/OWNERS.md has no row for it.";
; Where the agent logs episodes (AGENTS_ALPHABET.md: "Logs to .trinity/experience/").
pub const EXPERIENCE_LOG : str = ".trinity/experience/";
pub const ENABLED : bool = true;
Loading
Loading