Skip to content

refactor(global): one vocabulary on the wire, in the ledger and in the code - #138

Merged
rami-hatoum merged 38 commits into
mainfrom
refactor/one-vocabulary
Oct 9, 2026
Merged

rami-hatoum merged 38 commits into
mainfrom
refactor/one-vocabulary

Conversation

@rami-hatoum

@rami-hatoum rami-hatoum commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

The runtime now says what the product says, everywhere a person or a program can read it. A brain has definitions of a type, reasoning, interaction, computation, recall or workflow, and a definition carried out once is a run with a run_id. The HTTP routes, the MCP tools, their fields and values, the events a brain records, its stream names and tables, the settings, the package names and the code all use those words, and nothing serves the old names beside them: no alias, no mapping, no fallback. The product is not live, so this is the moment to change them once.

What a client of the HTTP API changes

Brain routes are relative to /v1/orgs/{org}/brains/{brain}.

Was Is
POST, GET /specs/{primitive} POST, GET /definitions/{type}
GET, PUT /specs/{primitive}/{name} GET, PUT /definitions/{type}/{name}
POST /specs/{primitive}/{name}/retire POST /definitions/{type}/{name}/retire
POST /specs/{primitive}/{name}/execute POST /definitions/{type}/{name}/run
GET /executions GET /runs
GET /executions/{execution_id} GET /runs/{run_id}
GET /executions/{execution_id}/history GET /runs/{run_id}/history
POST /executions/{execution_id}/cancel POST /runs/{run_id}/cancel
POST /executions/{execution_id}/events POST /runs/{run_id}/events
POST /executions/{execution_id}/answer POST /runs/{run_id}/answer
path values inference, recollection, orchestration reasoning, recall, workflow; interaction and computation unchanged
body execution_id of a run run_id
query primitive of GET /executions and GET /analytics type, with the new values, as GET /analytics?days=7&type=reasoning
query execution_id of GET /events run_id
answer specs of a listing of definitions definitions
answer executions of a listing of runs runs
primitive of a definition, a listed definition, a run, a listed run and by_function[] type
spec_version of a run and a listed run definition_version
execution_id of a run, a listed run, interactions[] and the answer of sending an event run_id
event type values execution_started, execution_deferred, execution_succeeded, execution_rejected, execution_failed, execution_cancel_requested, spec_created, spec_updated, spec_retired, in list_brain_events' answers and its type filter run_started, run_deferred, run_succeeded, run_rejected, run_failed, run_cancel_requested, definition_created, definition_updated, definition_retired
an event's data.execution_id, on every event of a run, workflow_input_applied, telling_started, and a call's step_waiting data.run_id
an event's data.primitive and data.spec_version data.definition_type and data.definition_version
data.called_by.execution_id, data.emitted_by.execution_id data.called_by.run_id, data.emitted_by.run_id
sources a published event may not use: /executions/, /specs/, /callers/ /runs/, /definitions/, /callers/
a fact's source /executions/<id>, /specs/<primitive>/<name>, and subject <primitive>/<name>, in a trigger or a recall filter /runs/<id>, /definitions/<type>/<name>, <type>/<name>, as reasoning/triage
the metadata key a tool server receives with a run's call, com.beonauto/execution_id com.beonauto/run_id
the settings ORCHESTRATION_MAX_DURATION, ORCHESTRATION_SWEEP_INTERVAL, ORCHESTRATION_NESTED_EXECUTIONS, ORCHESTRATION_MAX_OPEN_CALLS, RECOLLECTION_MAX_FUNCTIONS, RECOLLECTION_MAX_REBUILDS, RECOLLECTION_BRAINS_AT_ONCE WORKFLOW_MAX_DURATION, WORKFLOW_SWEEP_INTERVAL, WORKFLOW_NESTED_RUNS, WORKFLOW_MAX_OPEN_CALLS, RECALL_MAX_FUNCTIONS, RECALL_MAX_REBUILDS, RECALL_BRAINS_AT_ONCE
the log annotation execution_id run_id

A type no capability of the server serves is refused with 422 invalid_input at /type, naming the types the server runs, on every route and tool that takes one, where it answered 404 on a definition's routes and an empty page on GET /runs and GET /analytics. A definition's type is type on a resource, and definition_type on a record whose own type already names the record: a ledger event, the data of a brain event, the data of a fact. Unchanged for a client: every other route, the problem types, reasons, kinds and because values, the JSON Schema identifiers, the scopes, /health and the three MCP endpoints. The detail of a problem and the summary of an event are words for people and change only where they named a tool or an old word.

A workflow document calls a definition with call: run_definition and with: { type, name, input }, and its $runtime.metadata is { type: 'workflow' }.

What an agent sees

Eleven tools are renamed and fourteen keep their names; /mcp still serves 25, a key's org endpoint 8 and a brain's endpoint 19.

Was Is
create_spec, list_specs, get_spec, update_spec, retire_spec create_definition, list_definitions, get_definition, update_definition, retire_definition
execute_spec run_definition
get_execution, list_executions, get_execution_history, cancel_execution get_run, list_runs, get_run_history, cancel_run
send_execution_event send_run_event

The tools take and answer the fields of the HTTP table. The served instructions no longer carry the sentence that told an agent how to translate the tools' names into the product's words, since there is nothing left to translate; they are 100 characters shorter on /mcp and on a brain's endpoint. The recipes and every tool description name the new tools, each within its bounds.

What the ledger records

A run records on its own stream, runs/<id>, and the workflow engine's run log on run-logs/<id>, a different kind, so the two streams of a run stay apart; a server test checks that no stream of the runs/ kind begins with a run-log event. A brain's definitions of one type are the stream definitions/<type>. The nine event types and the fields above are recorded under their new names. The projections that fold runs take their next versions, run_outcomes_3 (with the column definition_type), open_requests_5 and conversations_2, filled from history by the next server, which drops the versions before. The workflow host keys a run by run_key, the host's org/brain/<id>, beside brain_key, and its reaction backlog keeps the bare run_id. Because every stream name changes, every message id changes with it.

A local database made before this change

Nothing reads the old names, so there is no migration. Delete packages/server/.data/ledger.db for pnpm dev, or the file LEDGER_FILE names, or the PostgreSQL database DATABASE_URL names, before running this build on it. Kept, such a database shows no definition and reads its run logs as runs. The workflow host makes its tables with CREATE TABLE IF NOT EXISTS, so a kept database keeps their old run_id columns: the server starts, and then every read and write of the host's run tables fails, so no workflow run can be recorded, and the due, timer and deferred-start sweeps die on every pass.

The engine's format 7

The workflow engine names its run runId in its state, its inputs, every output an event carries, its call keys and its snapshots, which is state format 7. Format 6 is frozen: its state is read strictly and upcast by renaming executionId to runId, and the event and snapshot schemas of formats 1 to 6 are frozen with it, so each event and snapshot is read with the schemas of the format it names. The corpus gains a format-7 log and keeps formats 1 to 6 loading, and the recorded input logs are recorded again under format 7.

The packages

primitives/ is capabilities/: @beonauto/inference is @beonauto/reasoning, @beonauto/orchestration is @beonauto/coordination, @beonauto/recollection is @beonauto/recall, and @beonauto/specs is @beonauto/definitions, with the same subpaths. The contract a capability package implements is Capability, declared with defineCapability; it states its type and runs a definition with run. A definition's type is its one discriminator: FunctionType (reasoning, interaction, prediction, recall, computation) replaces the verb kinds, and the published taxonomy asset carries type at schema 2. The Dream note is removed; the concepts page already says what it said.

Verification

  • pnpm check, without PostgreSQL and against PostgreSQL 18.
  • The image's smoke steps of the CI workflow, run against an image built from this change.
  • A search test kept in pnpm docs:test finds none of the old words outside docs/decisions, patches/, the lockfile, the frozen engine formats and readers of formats 1 to 6, and the check of internal terms and its test, which must name what they refuse. It allows, each only in the files that use it, the addresses of the Open Workflow Specification's error types and of the CloudEvents specification, the model providers' terms inferenceConfig, inferenceGeo, inference-profile and "application inference profile", toolSpec, code_execution, the model SDK's execution-denied, and the sentence of CLAUDE.md that says what inference names; it fails when an allowed text stops occurring.

rami-hatoum and others added 30 commits October 9, 2026 12:02
…dger, by script

The packages move to the product's words: primitives/ to capabilities/,
inference to reasoning, orchestration to coordination, recollection to
recall, and packages/specs to packages/definitions, with their package
names, imports, workspace files and lockfile. primitives/dream goes.

Identifiers and texts follow the word tables: a definition's type is
`type` on a resource and `definition_type` on a record whose own `type`
names it, a run is `run_id`, the host keys a run by `run_key`, the run
log's streams are `run-logs/<id>` and a run's are `runs/<id>`, and the
tools, routes, event types, settings and stream kinds take the new
names. The engine's frozen formats, the internal-terms check, the input
logs and the provider terms are left for the steps that own them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A run's start and a definition's facts copy the run's type into the
record as `definition_type`; the registry takes a capability's `type`;
a prepared definition runs with `run`. The run log's kind is
`run-logs` where the follower, the presenters and the feeds test it,
and the run outcomes match a run's stream by `runs/`.

A definition's `type` is its one discriminator: `FunctionType` and
`functionTypeOrder` replace the verb kinds, the labels, nouns and
descriptions are keyed by type, and the taxonomy asset carries `type`
at schema 2.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ype is named as one

A capability's tests read its `type` where they read its `name`, a
workflow's call that lacks a type says it needs "a string type", and a
route or call naming a type no capability serves answers "There is no
definition type ...". A recall run's recorded output bytes are 70, the
size of an output that names its run by `/runs/<id>`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rough the run route

The function in the test is named graph, so its route ends graph/run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…the tests speak of types

get_brain_analytics filtered by `type` handed the run outcomes a `type`
they do not read, so a filter kept every run; it hands them the
`definitionType` they select by. The brain events of a definition and of
a run's start carry `definition_type` in their data, which the
presenters' tests now expect; an unknown or malformed type is refused at
`/type`; the compiled capability fixtures declare `type` and `run`; and
`workflow` and `recall`, now types, leave the list of names that are not.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
No tool name carries an old word, so the sentence that told an agent
what the tools call a definition, a run and a type is deleted with
`wireWords`, `wireNames`, its place in `orientation` and its tests. The
instructions take 1,890 characters on /mcp, 1,495 on the org endpoint
and 1,850 on a brain's; a key that may only read keeps 1,573, 1,610,
1,468 and 1,573, as decision 0007 measured them.

The check of internal terms finds `recollection` too, and the README
quotes the instructions as served.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
create_definition's description says `type` where the rename left
`capability`, which makes it 788 characters in five sentences, the
longest of the 25 tools. run_definition's says "a run_id", 774
characters. The type field of a definition, a run and the analytics
says which types there are: reasoning, interaction, computation,
recall or workflow, and the analytics order "by type and name".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The recipes take 1,764, 1,762, 2,049 and 1,285 bytes, and first-brain
and give-tools 1,854 and 2,309 where interaction functions are served;
each of the four is pinned now, with and without them.
create_definition's description is pinned as the longest, at 788
characters in five sentences. The instructions are searched for
internal terms whole, since no sentence maps the wire names any more,
and a key that may only read finds the sentence on get_guide after the
one on its brains.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The served instructions without the wire sentence, the tool descriptions
and recipes at their measured sizes, and the type field described by its
values.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…uct's words

The bulk rename left sentences that translate the API, wrong articles and
"capability" where a definition's type is meant. The references say
"The `type` field names the type of a definition" and each format page
"a definition of the type ...", the MCP references lose the clause on the
sentence that mapped the wire names, the terminology page takes the four
rewordings of runs, and CLAUDE.md takes the five passages of 0007 word for
word. A fact's data says `definition_type`, a run log is `run-logs/<id>`,
and TODO.md gains the line on a ledger made before the one vocabulary in
place of the two it makes moot.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e names things

A capability states its `type` and runs a definition with `run`, the
records that carry their own `type` say `definition_type`, the ledger's
selection and outcome rows say `definitionType`, a run log is
`run-logs/<id>` and the engine's port `RunLogStore`, the host keys a run by
`run_key`, and the capability folders say `src/capability` and `src/runs`.
The capability READMEs lose the sentence that named their API identifier,
the API README the account of the instructions' wire sentence, with the
instructions' lengths of 0007, and the projections of runs take their next
versions. The engine's State formats gain format 7 and the rule that an
event and a snapshot are read with the schemas of the format they name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e copies its packages in order

The smoke's file for the answer of `run_definition` took the run's word,
as 0007 asks of a test's variable for a run. The Dockerfile lists the
definitions package and the capability folders in alphabetical order
again, as it listed the packages before the move.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d texts

The quote of the instructions on `/mcp` and the paragraph with their
lengths are the served texts' to change with the code that serves them;
this README keeps only what 0007's section 1.3 removes from it, the
sentence on the values the tools take and the account of the wire sentence.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rojections take new versions

The in-memory read of the runs of one definition matches the start's
definition_type, as the stores do. run_tallies and topics fold the kind
runs, which now names a run's stream, so they take run_tallies_2 and topics_2.
read_run_tallies answers each group's type. The paging test's records
and presenter share the run log's kind.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…dex measures definitions/

The outcomes of runs fold the kind runs and keep the column
definition_type, so the table is run_outcomes_3; its row and the groups
the stores read carry the column's own name. The SQLite expression of
ledger_definition_streams compares the 12 characters of definitions/.
A ledger fills topics_2 and drops topics_1, as it does run_tallies_3
and run_outcomes_3.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ition type as records do

The facts of runs and definitions carry data.definition_type in their
tests, a start's summary names definitionType, a run's type says what
values it takes, and workflow and recall are types now, so a run of
them is no longer a run of an unknown type.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…n log is run-logs/<id>

The row schemas whose column is run_key name it so, which the timer
loop, the sweeps and the listeners decode; a listener's own emission is
emitter.runId against addressOfRun(row.run_key).runId.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…un's stream under its kind

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The search finds the patterns of primitive, spec, execution, inference,
orchestration and recollection, and execute_spec, /execute and
executeSpec, outside the records, the lockfile, the patches, the frozen
formats and itself, but the texts it allows, and fails when an allowed
text no longer occurs or a file it leaves out is no longer tracked.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The documentation, CLAUDE.md, TODO.md, the package READMEs, the smoke
steps and the image in the product's words.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…fines it

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The ledger's run outcomes at run_outcomes_3 with definition_type, the
other projections at their next versions, the definition streams'
SQLite index over definitions/, the host's row keys by run_key, and the
search test of the repository.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ned for recollection

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ds of its refusal

The conflict a cancel meets said "The run runs within the call"; it says
the run takes place there.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s read by their format

The state, its call keys, the outputs of an event and the envelope of a
snapshot name the run `runId`, so `stateFormat` is 7. Format 6 is frozen
in `format-six.ts`, read strictly and upcast by naming the run `runId`
in the state, its calls and listeners and every call frame; what a run
holds as data keeps its words. The events and snapshots of formats 1 to
6 are frozen in `format-six-records.ts`, outputs, call keys and the
settlement among them, and `RunLogEventSchema` and `SnapshotSchema` read
each record with the schemas of the format it names, strictly for an
older one, and write it back with its own names. An older event is
measured as it was written, so its bytes are those its history counted.

The corpus gains `format-7.json`, recorded by this code, and its test
reads every committed stream and snapshot, formats 1 to 7, by its own
format, writes it back as committed and loads it to the state it
recorded. The README's rule says an event and a snapshot are read with
the schemas of the format they name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Recorded with RECORD_INPUT_LOGS=1. Against the logs before, after the
renames (`executionId` to `runId`, `execute_spec` to `run_definition`,
`primitive` to `type`, `inference` to `reasoning`, the error's "rejected
the run with" and the patch path `/runId`) and format 6 to 7, they differ
in 50 byte counts and nothing else: 33 `historyBytes`, 11 `heldBytes` and
6 `bytes` of a held value.

The presenter's test names the one stored type, `input_applied`, since the
event schema is now a union of the formats it reads.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… engine applied

After workflows that set, call a reasoning function, nest a workflow,
wait, listen, emit, fork and catch have started, the test reads the first
message of every stream of the brain from the ledger file and finds none
whose kind key, the name up to its fourth `/`, is `runs/` and whose first
message is `input_applied`; each run has its stream under `runs/` and its
log under `run-logs/`. A run log written under the run's kind fails it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The engine's state format 7 with formats 1 to 6 frozen and read by the
format they name, the corpus and the input logs recorded again, and the
test that no run's stream begins with a run-log event.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… tests of older formats

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
rami-hatoum and others added 8 commits October 9, 2026 13:08
…uns start in turn

The emitting workflow named a source its format refuses, so it was never
saved and its start answered not found.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Its description read "reasoning (reasoning function), ... or workflow
(workflow)"; it names the types, as "reasoning, interaction,
computation, recall, or workflow".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… definitionType

ReactionOptions, DiscoveryParts and StepParts said `type`, which names a
resource's own type; they say `definitionType`, as the projector does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…, each beside its test

The readers of formats 1 to 6 and format 6's frozen records, with their
tests, move to src/run-log/formats/, so run-log keeps twelve files. The
README's rule and the search test's frozen paths name the new folder.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… naming the types it runs

The type field checked the shape alone, so GET /runs?type= and
GET /analytics?type= with a type no capability serves answered an
empty page, and a definition's routes answered not found. Every
operation that takes a type now decodes it against the types its
capabilities serve and refuses another with invalid_input at /type,
over HTTP and MCP; a malformed type still names its shape alone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…easoning adapter names its run

`executing`, which named running a definition in the capabilities'
harnesses and the tests, is `running`, and the reasoning adapter's
run is `run`, as the interaction and recall adapters name theirs. The
ledger's command method, the engine's Executor and its tests keep the
verb.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… files that use each text

TODO.md says that a kept database keeps the host's old run_id columns,
so every read and write of its run tables fails and the due, timer and
deferred-start sweeps die on every pass. The terminology page says runs
are each time the work is done. The search test allows each text only
in the files that use it and fails when one of them stops; the example
tool of the reasoning reference is graph/query, so it needs none.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@rami-hatoum
rami-hatoum merged commit b753ded into main Oct 9, 2026
17 checks passed
@rami-hatoum
rami-hatoum deleted the refactor/one-vocabulary branch October 9, 2026 13:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant