Repository navigation
refactor(agents): behaviour from agent and template rows - #385
Merged
Merged
Conversation
8 tasks done
Operators write templates and agents as rows, but what embry0 did with one depended on the names of the built-in ones. An operator's own specialist template was triaged and offered to triage, its jobs' briefs said "the result of the work", and an agent of their own could never be given a task from the guild. The progression and world queries credited a job's pull request, cleanup and audit by template and agent names. Each of those is now a column of the row, read through one module, embry0/workflows/row_behaviour.py: - pipeline_templates.fixed_route (a job that names it skips triage), offered_to_triage, job_kind, delivers and leader_agent; - agent_definitions.station and quest_template (NULL no guild task, '' a task naming no template, else that template). SPECIALIST_TEMPLATE_NAMES, specialist_job_kind, _TEMPLATE_DELIVERS, LEADER_BY_TEMPLATE, QUEST_TEMPLATE_BY_AGENT, the frontend's STATION_OF and progression's _CODER are gone; the coding agents are listed once. A job's pull request is its template leader's when the leader codes (coder_sql and row_behaviour.coder, pinned to agree), else the developer's. The pipelines the code defines (qa, onboard, pr-review) keep their leader and deliverable in WORKFLOW_PIPELINES. Migration 143 adds the columns and writes every row what its name said, so an upgraded deployment behaves as before; the boot seed writes a built-in template's columns on its first insert only, like default_for_kind. The columns are set through the API (422 naming the field, including a leader or a task that names nothing), MCP agent_create and agent_update, the agent form's Guild section and a template's Behaviour dialog on the Pipelines page. The issue's agent roles column is left out: its one consumer would put an operator's agent on the developer node, a capability of its own. Refs: #167
Operators write templates and agents as rows, but what embry0 did with one depended on the names of the built-in ones. An operator's own specialist template was triaged and offered to triage, its jobs' briefs said "the result of the work", and an agent of their own could never be given a task from the guild. The progression and world queries credited a job's pull request, cleanup and audit by template and agent names. Each of those is now a column of the row, read through one module, embry0/workflows/row_behaviour.py: - pipeline_templates.fixed_route (a job that names it skips triage), offered_to_triage, job_kind (an override; NULL reads the route, so a route of specialists only is analysis), delivers and leader_agent; - agent_definitions.station and quest_template (NULL no guild task, '' a task naming no template, a coding agent's only, else that template). Credit is recorded on the job when it is planned: plan_route writes jobs.coding_agent and jobs.leader_agent, and progression and the world credit from them. A slop cleanup is a merged job the Slopmaster coded, an audit a job the context auditor led, so a copy of either template counts and a later edit of a template row changes no past credit. SPECIALIST_TEMPLATE_NAMES, specialist_job_kind, _TEMPLATE_DELIVERS, LEADER_BY_TEMPLATE, QUEST_TEMPLATE_BY_AGENT, the frontend's STATION_OF, progression's _CODER and AUDIT_TEMPLATE are gone; the coding agents are listed once. The pipelines the code defines (qa, onboard, pr-review) keep their leader and deliverable in WORKFLOW_PIPELINES, and no template may take their names. Migration 143 adds the columns and writes every row and job what its name gave it, and renames a template named like a code pipeline. The boot seed writes a built-in template's columns on its first insert only. The columns are set through the API (422 naming the field, checked only when a write changes the value), MCP agent_create and agent_update, the agent form's Guild section and a template's Behaviour dialog. A rename carries each agent's guild task with it. When the rows cannot be read, no route is fixed and the guild offers no task. Agent roles are left to #395. Fixes: #167
Operators write templates and agents as rows, but what embry0 did with one depended on the names of the built-in ones. An operator's own specialist template was triaged and offered to triage, its jobs' briefs said "the result of the work", and an agent of their own could never be given a task from the guild. The progression and world queries credited a job's pull request, cleanup and audit by template and agent names. Each of those is now a column of the row, read through one module, embry0/workflows/row_behaviour.py: - pipeline_templates.fixed_route (a job that names it skips triage), offered_to_triage, job_kind (an override; NULL reads the route, so a route of specialists only is analysis), delivers and leader_agent; - agent_definitions.station and quest_template (NULL no guild task, '' a task naming no template, a coding agent's only, else that template). Credit is recorded on the job: it takes its template's leader when it is created, plan_route writes jobs.coding_agent and jobs.leader_agent, and progression and the world credit from them, so a later edit of a template row changes no past credit. A slop cleanup is a merged job the Slopmaster coded. An audit is a job the context auditor led and not a fix job: one predicate (audit_jobs) for progression and the findings feed, which the scheduler counts too, with its own template's jobs. SPECIALIST_TEMPLATE_NAMES, specialist_job_kind, _TEMPLATE_DELIVERS, LEADER_BY_TEMPLATE, QUEST_TEMPLATE_BY_AGENT, the frontend's STATION_OF, progression's _CODER and AUDIT_TEMPLATE are gone; the coding agents are listed once. The pipelines the code defines (qa, onboard, pr-review) keep their leader and deliverable in WORKFLOW_PIPELINES, and no template may take their names. Migration 143 adds the columns and writes every row and job what its name gave it, and renames a template named like a code pipeline. The boot seed writes a built-in template's columns on its first insert only. The columns are set through the API (422 naming the field, checked only when a write changes the value), MCP agent_create and agent_update, the agent form's Guild section and a template's Behaviour dialog. A rename carries each agent's guild task with it, under the row's lock. When the rows cannot be read, no route is fixed and the guild offers no task. Agent roles are left to #395. Fixes: #167
sudoTomas
force-pushed
the
refactor/behaviour-from-rows
branch
from
November 6, 2026 16:10
b5467a6 to
dfeb003
Compare
8 tasks done
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
What embry0 did with a pipeline template or an agent by the built-in ones' names is now a column of its row: a template's
fixed_route,offered_to_triage,job_kind,deliversandleader_agent, and an agent'sstationandquest_template. A job records who coded it and who led its template when it is planned, and is credited from that. An operator's own templates and agents take part the way the built-in ones do. Fixes #167 (part of #159); agent roles follow in #395.Motivation — Intent + Problem
Operators write templates and agents as rows, but the behaviour around them was keyed by built-in names, so a template or agent of a deployment's own could not take part without a fork:
SPECIALIST_TEMPLATE_NAMES);_TEMPLATE_DELIVERS);QUEST_TEMPLATE_BY_AGENT,can_quest), and stood at a desk (STATION_OF);LEADER_BY_TEMPLATE), and progression credited a pull request, a cleanup and an audit by template and agent names in SQL (_CODER,AUDIT_TEMPLATEand the event literals; the world's cleanup count likewise), so a copy of the context-audit template earned no audit;How it works
embry0/workflows/row_behaviour.py. A row without a column (a fake, an older summary) reads as the column's default, which is how a template or agent of the deployment's own behaved before.plan_route.pinned_template, the single lookup that already fetched its triage config);fixed_routeskips the classifier. Triage's template list leaves out a row withoffered_to_triagefalse, and plan_route drops triage's own pick of one (before the slop override, so hidingslop-cleanupfrom triage never turns off slop routing).default_for_kind, else itsjob_kindoverride, else what its route makes it as the route is now: every step but the output a specialist isanalysis(the oldspecialist_job_kindrule, read from the row's graph). A new specialist-only template is analysis; a specialist route given a coding step is not.jobs.leader_agent, so a pending job is known for what it is), and plan_route records it again withjobs.coding_agent(the agent its route's coding step runs as) and the job's kind. Progression and the world credit from those columns, never from today's template rows: a pull request is its coder's (the developer when it recorded none), and a slop cleanup is a merged job the Slopmaster coded (a copy ofslop-cleanupkeeps its Slopmaster step, so its merges are cleanups too). So an edit or a deletion of a template row later changes no past credit.embry0/storage/repositories/audit_jobs.py: a job the context auditor led (the agent whose report an audit's claims are read from), and not a finding's fix job. Progression (audited XP, lore claims, the clean_audit quest, audit_merged) and the findings feed both read it, so a copy ofcontext-auditearns audit credit and offers its findings, and acontext-auditjob planned after an operator gave the template another leader does neither. The scheduler counts every such audit for its cadence and live check, plus every job of its own template and every job it dispatched whatever led them: those work on the files an audit opens a pull request on, and after a leader change the scheduler must not start an audit again on every tick. The job it starts is always its own template's. The QA pipeline,onboardandpr-revieware never planned;WORKFLOW_PIPELINESholds their leader and deliverable once, and no template may take their names (422, on create, rename and duplicate).deliversastemplate_delivers; it is not part of the brief's input hash, so no existing brief is rewritten by the upgrade.GET /worldreads the agent and template rows (kept with the board for 60 s; an agent or template write forgets them, so a change shows on the next read). A character'sstationandcan_quest/quest_templatecome from its row:quest_templateNULL is no task,''a task naming no template (triage picks; only a coding agent's), a name that template; a task naming a template that no longer exists is no task. A party is drawn as the leader its job recorded, or before it is planned its template row's.POST/PUT /pipelines/templatesandPOST/PUT /agents, each value checked with a 422 naming the field, plusleader_agent: no agent named ... runs in jobs,quest_template: no pipeline template named ...andquest_template: ''for an agent that does not code. Only a value the write changes is checked: the forms send every field, and a stored task or leader that went stale does not stop a save. A template rename moves every agent'squest_templatethat named it, in the same transaction, reading the old name under the row's lock so two renames at once carry the task to the final name. OnPUT, null clearsjob_kind,leader_agentandquest_templateand is a 422 for the NOT NULL columns. The agent reads carry a read-onlycoding_agent. MCPagent_create/agent_updatetakestationandquest_template;clear_quest_template=truesends the one null (there is no MCP template write tool). Dashboard: Guild on the agent form (the no-template task offered only to a coding agent); Behaviour… in a template's menu on the Pipelines page, with badges for "Skips triage" and "Runs only when named". A fixed route with aqastep is saved with a warning (only triage asks for QA).duplicatecopies the columns.builtin_template,builtin_agent).docs/contracts/identity.jsonstations, mirrored inagentIdentity.ts), each an object of the world art.Upgrade. Migration 143 adds the columns and writes every row what the code said of its name before, matched by name as the code matched it, and every existing job what the old name rules credited it with (a
slop-cleanupjob coded by the Slopmaster, each job led by its template's old leader; the backfill does not movejobs.updated_at).job_kindstays NULL: the graph gives what the old rule did. A template namedqa,onboardorpr-reviewis renamed<name>-template(with its id's head when that is taken too); I did not query a running deployment for such rows. Built-in agents stay insert-if-missing. Built-in templates are upserted at boot: the new columns followdefault_for_kindand are written on a first insert only, so an operator's change survives a restart (test).row_behaviourandservices.slopjoin the rollup'sFOLD_MODULES, so this release rebuilds the progression rollup once.Proof that a deployment with only built-in rows behaves the same.
tests/fixtures/name_lists_before_rows.pykeeps the removed lists and rules as they stood;test_row_behaviour.pychecks every built-in template, code pipeline and agent against them (fixed, offered, kind, leader, the coder plan_route records, what a brief says for every kind; station and guild task), andtest_migration_143.pychecks an upgraded database's rows and jobs the same way. The progression golden test (test_progression_golden.py, raw and through the rollup) passes with its recorded file unchanged.Pattern provenance
N/A — originated in this PR. The column, seed and write-path handling follows
agent_definitions.triage_may_add_skills(migration 142) andpipeline_templates.default_for_kind.Verification
Automated
-n 4 --fail-on-warnings,DOCKER_HOST=unix:///nonexistent.sock:18867 passed, 21 skipped in 514.04s(the 15 Docker-backed infra tests among the skips, as on main)ruff check .,ruff format --check .(whole tree),mypy embry0: cleancd frontend && npm run lint: 0 errors (5 warnings, all pre-existing in files this PR does not touch)cd frontend && npx tsc -bandnpm run build: succeedcd frontend && npm run test: 328 files, 2676 tests passedscripts/check_denylist.py --public): 0 matches; gitleaks on the changed files: no leaksEach new test failed first. Against
origin/main(the first commit's tests): routing from rows, the guild's world API, the API write paths, migration 143, MCP and the name-list pin each failed with their own assertions;test_row_behaviour.pyandtest_behaviour_rows_repo.pyfail at import there and were also shown failing by mutation. Against the PR's first commit (e11e71dd, the review findings' tree), the tests for the findings fail with their own messages:test_a_job_keeps_the_credit_it_recorded_whatever_its_template_row_says_later,test_an_audit_is_a_job_the_context_auditor_led,test_plan_route_records_who_codes_the_job_and_who_leads_its_template,test_a_planned_party_is_drawn_as_the_leader_it_recorded,test_an_upgrade_credits_each_job_as_its_name_did;test_a_save_that_keeps_a_stored_task_or_leader_is_not_refused_for_it,test_a_rename_carries_each_agents_guild_task_with_it;''for a coding agent only:test_a_task_naming_no_template_is_a_coding_agents_only(API and helper), and the agent form no longer offering it to another agent;_offered_to_triage;test_a_template_cannot_take_a_code_pipelines_name(API and helper),test_a_template_named_like_a_code_pipeline_is_renamed;AUDIT_TEMPLATEgone, and "a past job's credit must not move with today's template rows".Against the PR's second commit (the last review's tree), the last two findings' tests fail first:
test_progression_the_findings_feed_and_the_scheduler_agree_on_what_an_audit_is("the findings feed offers what progression counts as audits: ['acme/changed', 'acme/scheduled']"), andtest_a_job_that_names_a_template_takes_its_leader_when_it_is_created;test_two_renames_at_once_carry_the_task_to_the_last_nameholds the row from a second session until both renames wait on it ("template now beta, the agent's task gamma: a rename read a stale name"); it fails the same way, three runs of three, with theFOR UPDATEtaken out, and passes five runs of five with it.Existing tests changed, and why
test_specialist_agents.py,test_triage_fixed_route.py,test_world.py,test_developer_salvage.py); the fake templates repository intest_specialist_agents.pycarries the seed's behaviour columns, as real rows do, and plan_route's job update now also writescoding_agentandleader_agent.tests/fixtures/builtin_rows.planned_credit): the progression history fixture behind the golden test, and helpers intest_progression_repo.py,test_fix_job_progression.py,test_quest_job_times.py,test_quests.py,test_progression_rollup.py,test_world_api.pyand the golden test's quest-scroll case. Their assertions are unchanged.test_proposals_repo.py) give their context-audit jobs the leader such a job records, and the five fake job repositories of the context-audit tests take the scheduler's newleader_agentargument.test_migration_142.pyhands the "last entry" assertion to 143; the MCP tool surface and forwarding tests list the new parameters;TemplateActions.test.tsx,pipelines.test.tsandworldHall.test.tsfollow the new menu item, mapping and the removed map.Manual
Deploy notes
qa,onboardorpr-review.Out of scope / follow-ups
generic_agent.py(the watcher log tool foranalysis, the task forcontext-auditor,GENERIC_AGENT_TIMEOUT_SECONDS), plan_route'sSLOP_TEMPLATEpick, and the achievement fragments andproposals.pythat name the templates their features dispatch (map-areas,pr-followup,context-audit).agent_updatecannot clearexecution_modeorauth_mode(pre-existing:_drop_nonedrops every null).Design + Plan
docs/superpowers/specs/2026-11-05-behaviour-from-rows-design.mdAnti-goals respected
Checklist
type(scope): short subject