From 8c5364e7a65aa1e1da9eb78a09f578621dc547fc Mon Sep 17 00:00:00 2001 From: Yvette Carlisle Date: Wed, 10 Jun 2026 02:10:46 +0800 Subject: [PATCH] {"schema":"decodex/commit/1","summary":"Wire natural-language research trigger into Decodex plugin surface","authority":"XY-858"} --- apps/decodex/src/lib.rs | 1 + apps/decodex/src/plugin_surface_tests.rs | 92 ++++++++++++++++++++++ plugins/decodex/.codex-plugin/plugin.json | 8 +- plugins/decodex/skills/automation/SKILL.md | 22 ++++++ plugins/decodex/skills/decodex/SKILL.md | 43 ++++++++-- plugins/decodex/skills/labels/SKILL.md | 12 ++- plugins/decodex/skills/planning/SKILL.md | 25 ++++++ 7 files changed, 194 insertions(+), 9 deletions(-) create mode 100644 apps/decodex/src/plugin_surface_tests.rs diff --git a/apps/decodex/src/lib.rs b/apps/decodex/src/lib.rs index ab3975ba..125cfe03 100644 --- a/apps/decodex/src/lib.rs +++ b/apps/decodex/src/lib.rs @@ -89,4 +89,5 @@ fn install_panic_hook() { })); } +#[cfg(test)] mod plugin_surface_tests; #[cfg(test)] mod test_support; diff --git a/apps/decodex/src/plugin_surface_tests.rs b/apps/decodex/src/plugin_surface_tests.rs new file mode 100644 index 00000000..cfeff2ed --- /dev/null +++ b/apps/decodex/src/plugin_surface_tests.rs @@ -0,0 +1,92 @@ +use serde_json::Value; + +const PLUGIN_JSON: &str = include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/../../plugins/decodex/.codex-plugin/plugin.json" +)); +const DECODEX_SKILL: &str = include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/../../plugins/decodex/skills/decodex/SKILL.md" +)); +const PLANNING_SKILL: &str = include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/../../plugins/decodex/skills/planning/SKILL.md" +)); +const AUTOMATION_SKILL: &str = include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/../../plugins/decodex/skills/automation/SKILL.md" +)); +const LABELS_SKILL: &str = include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/../../plugins/decodex/skills/labels/SKILL.md" +)); + +#[test] +fn packaged_plugin_manifest_routes_natural_language_research_to_decodex() { + let manifest: Value = serde_json::from_str(PLUGIN_JSON).expect("plugin manifest should parse"); + let interface = manifest + .get("interface") + .and_then(Value::as_object) + .expect("plugin interface should be an object"); + let long_description = interface + .get("longDescription") + .and_then(Value::as_str) + .expect("longDescription should be a string"); + let default_prompts = interface + .get("defaultPrompt") + .and_then(Value::as_array) + .expect("defaultPrompt should be an array") + .iter() + .filter_map(Value::as_str) + .collect::>() + .join("\n"); + + assert_contains(long_description, "natural-language-first"); + assert_contains(long_description, "\"research X\""); + assert_contains(long_description, "latent Decision Contracts"); + assert_contains(long_description, "\"arrange this\""); + assert_contains(long_description, "\"推进\""); + assert_contains(long_description, "queues only ready nodes"); + assert_contains(long_description, "graph, DAG, goal, and queue mechanics backstage"); + assert_contains(&default_prompts, "Research how Decodex should handle this."); + assert_contains( + &default_prompts, + "Arrange the accepted Decodex research contract into executable issues.", + ); +} + +#[test] +fn packaged_skills_preserve_research_promotion_and_queue_boundaries() { + assert_contains(DECODEX_SKILL, "## Natural-Language Research Routing"); + assert_contains(DECODEX_SKILL, "`research X`"); + assert_contains(DECODEX_SKILL, "latent Decision Contract"); + assert_contains(DECODEX_SKILL, "`arrange this`"); + assert_contains(DECODEX_SKILL, "`推进`"); + assert_contains(DECODEX_SKILL, "Do not queue work"); + assert_contains(DECODEX_SKILL, "Queue labels are an intake signal"); + assert_contains(PLANNING_SKILL, "accepted Decision Contract"); + assert_contains(PLANNING_SKILL, "Do not use planning to turn a plain `research X`"); + assert_contains(PLANNING_SKILL, "queue only mapped issues"); + assert_contains(PLANNING_SKILL, "Promotion is a separate authority boundary"); + assert_contains(AUTOMATION_SKILL, "Automation starts only after execution authority exists"); + assert_contains_normalized( + AUTOMATION_SKILL, + "latent research must not dispatch retained lanes", + ); + assert_contains(AUTOMATION_SKILL, "accepted/promoted Decision Contract"); + assert_contains(AUTOMATION_SKILL, "blocked, stale, paused, active, terminal"); + assert_contains_normalized(LABELS_SKILL, "not the user-facing research/design workflow"); + assert_contains(LABELS_SKILL, "accepted/promoted Decision"); + assert_contains(LABELS_SKILL, "Do not ask ordinary users to apply queue labels"); +} + +fn assert_contains(haystack: &str, needle: &str) { + assert!(haystack.contains(needle), "expected packaged plugin content to contain `{needle}`"); +} + +fn assert_contains_normalized(haystack: &str, needle: &str) { + let normalized_haystack = haystack.split_whitespace().collect::>().join(" "); + let normalized_needle = needle.split_whitespace().collect::>().join(" "); + + assert_contains(&normalized_haystack, &normalized_needle); +} diff --git a/plugins/decodex/.codex-plugin/plugin.json b/plugins/decodex/.codex-plugin/plugin.json index d195c91e..ae7814c8 100644 --- a/plugins/decodex/.codex-plugin/plugin.json +++ b/plugins/decodex/.codex-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "decodex", "version": "0.1.0", - "description": "Agent-facing workflows for planning, using, and operating Decodex in manual CLI and runtime-owned automation modes.", + "description": "Agent-facing workflows for Decodex research/design intake, planning, manual CLI use, and runtime-owned automation.", "author": { "name": "hack-ink", "email": "hi@hack.ink", @@ -20,8 +20,8 @@ "skills": "./skills/", "interface": { "displayName": "Decodex", - "shortDescription": "Use Decodex manually or as an automated retained-lane control plane.", - "longDescription": "Routes Codex agents through Decodex's planning and usage surfaces: Decodex-friendly issue splitting, queue shaping, and concurrency; manual CLI development workflows such as commit, land, status, project registration, account selection, and dry runs; and runtime-owned automation workflows such as serve, registered project contracts, Linear labels, tracker tools, review handoff, landing, closeout, and operator status. The plugin keeps Decodex-specific instructions with the Decodex runtime instead of duplicating them in generic playbooks.", + "shortDescription": "Use Decodex for research/design intake, planning, manual CLI work, or retained-lane automation.", + "longDescription": "Routes Codex agents through Decodex's natural-language-first surfaces: ordinary requests like \"research X\" enter Decodex-native research/design and produce latent Decision Contracts rather than automatic implementation; later follow-ups such as \"arrange this\", \"push this forward\", \"推进\", or \"做\" can promote accepted contracts into planning and issue shaping; planning splits accepted work into normal Linear issues and queues only ready nodes through registered project policy; manual CLI workflows such as commit, land, status, project registration, account selection, and dry runs stay explicit; and runtime-owned automation workflows such as serve, registered project contracts, Linear labels, tracker tools, review handoff, landing, closeout, and operator status keep their narrow authority. The plugin keeps graph, DAG, goal, and queue mechanics backstage for ordinary users while preserving Decodex-specific instructions with the runtime instead of duplicating them in generic playbooks.", "developerName": "hack-ink", "category": "Development", "capabilities": [ @@ -32,6 +32,8 @@ "privacyPolicyURL": "https://github.com/hack-ink/decodex", "termsOfServiceURL": "https://github.com/hack-ink/decodex", "defaultPrompt": [ + "Research how Decodex should handle this.", + "Arrange the accepted Decodex research contract into executable issues.", "Use Decodex to inspect this lane.", "Split this feature into Decodex-friendly independent issues.", "Run the Decodex automation preflight.", diff --git a/plugins/decodex/skills/automation/SKILL.md b/plugins/decodex/skills/automation/SKILL.md index 81b2ed25..53cbb14c 100644 --- a/plugins/decodex/skills/automation/SKILL.md +++ b/plugins/decodex/skills/automation/SKILL.md @@ -9,6 +9,13 @@ description: "Use for Decodex runtime-owned automation: registered projects, `se Operate Decodex as the retained-lane control plane for automatic development. +Automation starts only after execution authority exists. A natural-language +`research X` request can create a latent Decision Contract, but latent research must +not dispatch retained lanes, set Codex goals, mutate tracker state, or apply queue +labels. A later promotion request such as `arrange this`, `push this forward`, `推进`, +or `做` may feed planning and ready-node queueing only after the accepted contract is +clear. + ## Governing Surfaces - `project.toml` under `~/.codex/decodex/projects//` owns repo paths, @@ -87,6 +94,21 @@ on the next 15-second control-plane tick and still respects tracker rate-limit b silently retry. - Use the `labels` skill before adding, clearing, or interpreting these labels. +For research-to-execution work, automatic intake also requires: + +- an accepted/promoted Decision Contract or an equivalent explicit human instruction + that grants execution authority +- normal Linear issues with natural-language briefs, acceptance, dependencies, and + validation expectations +- readiness under the registered `WORKFLOW.md`, including startable state, dependency + policy, opt-out labels, active ownership, terminal-state rules, and local capacity +- queue labels only on ready issues; blocked, stale, paused, active, terminal, or + unmapped internal nodes remain unqueued + +Do not expose graph ids, DAG edge editing, hidden goal ids, or queue-label mechanics as +the ordinary user workflow. Operators may inspect status, but automation policy owns +the backstage readiness and intake mechanics. + ## Lane Completion The coding agent must leave exactly one terminal path for the leased issue: diff --git a/plugins/decodex/skills/decodex/SKILL.md b/plugins/decodex/skills/decodex/SKILL.md index 2bf1941d..f43d81be 100644 --- a/plugins/decodex/skills/decodex/SKILL.md +++ b/plugins/decodex/skills/decodex/SKILL.md @@ -8,8 +8,11 @@ description: Use as the conductor for Decodex work whenever the user asks to use ## Goal Route agent work through the right Decodex surface without duplicating the runtime -specs. Decodex has two supported use modes: +specs. Decodex has these supported use modes: +- Research/design mode: natural-language requests such as `research X` enter the + Decodex-native Research/Decision path. The result is a latent Decision Contract, + not execution authority. - Manual CLI mode: a human is driving local development, commits, PR preparation, landing, status inspection, project registration, account selection, or dry-run checks. @@ -17,10 +20,35 @@ specs. Decodex has two supported use modes: contracts, `serve`, `run`, tracker labels, issue-scoped tools, review handoff, landing, closeout, and operator status. - Planning support: agents shape Decodex-friendly issue sets, queue strategy, - dependency boundaries, and concurrency before retained-lane automation starts. -- Research/design mode: Decodex compiles ambiguous planning intent into local - Decision Contracts with `decodex research compile`, then records acceptance with - `decodex research promote` before any execution authority exists. + dependency boundaries, and concurrency after a human request or accepted/promoted + Decision Contract needs executable issue shaping. + +## Natural-Language Research Routing + +Keep the everyday user surface conversational. Do not require the user to mention +Research Lanes, Decision Lanes, DAGs, Execution Programs, queue labels, or Codex goal +commands. + +Route by intent: + +1. If the user says `research X`, asks for a design investigation, or asks Decodex to + figure out what should be done before implementation, treat it as research/design + intake. Produce or update a latent Decision Contract with evidence, assumptions, + options, objections, non-goals, acceptance criteria, stop conditions, readiness, + and open decisions. Do not queue work, create execution authority, mutate tracker + state, or start implementation from the research request alone. +2. If the user later says `arrange this`, `push this forward`, `推进`, `做`, or an + equivalent follow-up that clearly accepts or promotes the prior contract, treat that + as promotion to execution authority. Preserve the accepted contract boundary; if + direction is still missing or contradictory, ask for the missing decision instead + of starting work. +3. After promotion, use `planning` to convert the accepted contract into normal + Linear issues with clear natural-language briefs, dependencies, acceptance, and + validation. Keep Execution Program and graph mechanics as internal readiness state. +4. Use `labels` and `automation` only for nodes/issues that are ready under the + registered project policy. Queue labels are an intake signal for retained lanes, + not a shortcut around blockers, opt-outs, terminal states, active leases, or + missing briefing. ## First Steps @@ -38,6 +66,11 @@ specs. Decodex has two supported use modes: - `land` for `decodex land`. - `labels` for Decodex Linear labels. +Use explicit `decodex research compile` and `decodex research promote` commands only +when the operator is asking for the manual CLI surface. Ordinary conversational +research/promotion should still follow the same latent-then-promoted authority +boundary without making the user learn the commands. + ## Authority Split - Runtime behavior belongs to `apps/decodex/src/` and `docs/spec/`. diff --git a/plugins/decodex/skills/labels/SKILL.md b/plugins/decodex/skills/labels/SKILL.md index ea72fd9a..38efbe75 100644 --- a/plugins/decodex/skills/labels/SKILL.md +++ b/plugins/decodex/skills/labels/SKILL.md @@ -9,6 +9,10 @@ description: Use when applying, clearing, or interpreting Decodex Linear labels Handle Decodex-related Linear labels without changing runtime ownership by accident. +Labels are retained-lane intake and ownership signals. They are not the user-facing +research/design workflow and they do not promote latent Decision Contracts by +themselves. + ## Label Catalog | Label | Meaning | @@ -53,7 +57,10 @@ If a project-scoped command supplies `--config `, read that project checks, dependency checks, or active-lease checks. 4. Ensure `decodex:manual-only` is absent. 5. Ensure any prior blocker behind `decodex:needs-attention` is resolved. -6. Add `decodex:queued:`. +6. For research-to-execution work, ensure the source is an accepted/promoted Decision + Contract or an equivalent explicit human execution instruction, not only a plain + `research X` result or latent contract. +7. Add `decodex:queued:`. ## Pause or Opt Out @@ -73,5 +80,8 @@ If a project-scoped command supplies `--config `, read that project - Do not use `decodex:active:` to mean "please start work". - Do not clear `decodex:needs-attention` just to silence a failed lane. - Do not add a service-scoped label for the wrong registered service. +- Do not ask ordinary users to apply queue labels, mention DAG/goal mechanics, or + manage internal readiness state just to move from research to execution; route that + through promotion, planning, and automation policy. - Use `land` when the task is really about human-driven PR landing. - Use `commit` when the task is really about human-driven commit creation. diff --git a/plugins/decodex/skills/planning/SKILL.md b/plugins/decodex/skills/planning/SKILL.md index 2939546a..46c2b826 100644 --- a/plugins/decodex/skills/planning/SKILL.md +++ b/plugins/decodex/skills/planning/SKILL.md @@ -14,6 +14,11 @@ Use this before queueing a broad feature, migration, or cleanup effort into Deco For durable issue text, pair this skill with the delivery plugin's `split` or `issue` skill, then use the `labels` skill when applying Decodex intake labels. +Use this after a natural-language promotion follow-up such as `arrange this`, +`push this forward`, `推进`, or `做` when the accepted Decision Contract is ready to +become executable work. Do not use planning to turn a plain `research X` request or +latent contract into queued implementation. + ## Read First - The registered project `project.toml` for `service_id`, repo path, worktree root, @@ -45,6 +50,20 @@ Each issue should have: Do not make the description only a machine-readable fenced block. Generic normal dispatch requires a usable briefing surface. +When issues come from an accepted/promoted Decision Contract, each issue should also +carry: + +- objective lineage back to the accepted contract in plain language +- the accepted scope, non-goals, constraints, objections, and stop conditions relevant + to that issue +- dependency and conflict-domain notes needed to decide whether the issue is ready +- validation expectations copied from the accepted contract, not from latent evidence + alone + +Keep internal Execution Program ids, graph edges, and goal mechanics out of the user +workflow. They may inform issue readiness, but the Linear issue remains the executable +brief. + ## Parallelism Rules - Split by ownership boundary, validation surface, or deployable behavior, not by @@ -78,6 +97,10 @@ dispatch requires a usable briefing surface. instead of flooding the queue with dependent work. 5. When a lane stops with `decodex:needs-attention`, resolve the recorded blocker before clearing the label or re-queueing. +6. When the source is a promoted Decision Contract, queue only mapped issues whose + dependencies, conflict domains, acceptance, validation expectations, and registered + workflow state make them ready. Leave blocked, stale, paused, active, terminal, or + unmapped nodes unqueued. ## Boundaries @@ -89,3 +112,5 @@ dispatch requires a usable briefing surface. user asks for automation or the registered workflow requires it. - Do not use parallelism as a reason to split one atomic behavior across dependent issues that cannot be validated or reviewed independently. +- Do not promote, accept, or execute a latent research/design result just because it + has proposed issue summaries. Promotion is a separate authority boundary.