diff options
| author | Craig Jennings <c@cjennings.net> | 2026-05-26 01:57:48 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-05-26 01:57:48 -0500 |
| commit | f9c72c817290bb5433e593b2a8d1cfaa25431d20 (patch) | |
| tree | fed103aec3faf75624a2a969fd67dea71e501a4d /.ai/workflows/startup.org | |
| parent | 98382929852b213f8dc8b1ba720cc0d1861159b6 (diff) | |
| download | rulesets-f9c72c817290bb5433e593b2a8d1cfaa25431d20.tar.gz rulesets-f9c72c817290bb5433e593b2a8d1cfaa25431d20.zip | |
refactor(workflows): split triage-intake into engine + source plugins
The triage-intake workflow had every source baked into one file, so adding or changing a source meant editing the workflow itself. I replaced it with a source-agnostic engine plus per-source plugins named triage-intake.<source>.org. The engine carries the anchor/sentinel logic, the four-bucket model, the Phase A-D orchestration, the todo.org persistence convention, and the exit criteria. Each source's scan, classify, render, and action knowledge moved into its own plugin.
Four general plugins ship in the template: personal-gmail, personal-calendar, cmail, and github-prs. Project-specific sources live in the project's .ai/project-workflows/ and are never synced. Phase 0 globs both directories so a project source can't silently drop out of the sweep.
I taught INDEX.org and the startup workflow-discovery drift check the namespace. A file matching <engine>.*.org is a plugin of that engine, not an orphan, and gets no trigger entry of its own. A "run the triage-intake workflow" request routes to the engine, never to a plugin.
Diffstat (limited to '.ai/workflows/startup.org')
| -rw-r--r-- | .ai/workflows/startup.org | 6 |
1 files changed, 4 insertions, 2 deletions
diff --git a/.ai/workflows/startup.org b/.ai/workflows/startup.org index 8aa420c..2371d11 100644 --- a/.ai/workflows/startup.org +++ b/.ai/workflows/startup.org @@ -158,12 +158,14 @@ Two directories hold workflows: - =.ai/workflows/= — template workflows (synced from claude-templates, never edit in project). - =.ai/project-workflows/= — project-specific workflows (never touched by sync). +*Engine + plugin naming convention.* A workflow file may be an *engine* that owns *source plugins*. The convention is dot-delimited: =engine-name.org= is the engine; =engine-name.plugin-name.org= is a plugin of it. The first dot after the engine name is the engine/plugin boundary; hyphens stay *inside* a segment (=triage-intake.personal-gmail.org= is engine =triage-intake=, plugin =personal-gmail=). The glob =engine-name.*.org= matches the plugins but not the engine (the engine has no second dot-segment), so an engine never loads itself. Deeper dots (=engine-name.plugin-name.sub-name.org=) are reserved for sub-adapters — unused for now, accommodated at no cost. This generalizes: any future engine =foo.org= owns =foo.*.org= plugins. Plugins are not independently triggerable — they have no index entry, and a "run the [engine] workflow" request always routes to the engine, never a plugin. + When the user says "let's run/do the [X] workflow" (or otherwise references a workflow by topic): 1. *Read =.ai/workflows/INDEX.org=.* It maps trigger phrases to workflow filenames so you don't have to read each workflow's "When to Use" section to route. Project-workflows aren't in the index — handle those via =ls= in step 2. 2. *List both directories:* =ls -1 .ai/workflows/ .ai/project-workflows/ 2>/dev/null=. -3. *Drift check.* Compare the =.org= files in =.ai/workflows/= against the entries in INDEX.org (excluding INDEX.org itself). If an index entry points at a deleted file, or a file in the directory has no index entry, surface the mismatch to the user and offer to update INDEX.org. Don't silently route around it. -4. *Match the request* against the index trigger phrases first, then against project-workflow filenames if no index hit. +3. *Drift check.* Compare the =.org= files in =.ai/workflows/= against the entries in INDEX.org (excluding INDEX.org itself). If an index entry points at a deleted file, surface the mismatch and offer to update INDEX.org. If a file in the directory has no index entry, first test whether it's a *source plugin* — any file matching =<indexed-engine>.*.org= (a second dot-segment after an indexed engine name) belongs to that engine and is correctly absent from the index; do not flag it. Flag only genuine orphans: a non-plugin =.org= with no entry. Don't silently route around real drift. +4. *Match the request* against the index trigger phrases first, then against project-workflow filenames if no index hit. A request matching an engine routes to =engine-name.org=, never to one of its =engine-name.plugin-name.org= plugins — the engine loads its own plugins at run time. 5. *Read and execute* the matching file. 6. *No match* → offer to create via =create-workflow=; new workflows go to =.ai/project-workflows/= and project-specific ones don't go in INDEX.org. 7. *Project extension.* As one of the very last steps in the matched workflow's flow, check if =.ai/project-workflows/= contains a file with the same name as the template that just ran. If yes, read and execute it as *additional* steps appended to the workflow — not a replacement. The project file contains add-on steps that pick up where the template's main flow ends. Surface the extension once per session ("Project has additional steps for send-email.org — running them now"). Only applies when the matched workflow came from =.ai/workflows/=; project-only workflows have no template to extend. This mirrors the startup-extras.org pattern: projects extend template behavior without forking the template repo. |
