Skip to content

docs(openspec): Propose local-rule-routing change - #23

Merged
thecodedrift merged 68 commits into
mainfrom
feat/local-rule-routing
Jun 15, 2026
Merged

docs(openspec): Propose local-rule-routing change#23
thecodedrift merged 68 commits into
mainfrom
feat/local-rule-routing

Conversation

@thecodedrift

@thecodedrift thecodedrift commented Jun 11, 2026

Copy link
Copy Markdown
Member

Establish the OpenSpec change contract for a local-first rule-routing layer in the Taskless CLI and skill.

Today authoring a rule routes straight to the login-gated rule create, which runs generation off the developer's machine, and the skill suppresses itself whenever a user names a linter (eslint, ruff, biome) — stepping back from exactly the requests where Taskless could help author the rule in that tool's dialect. This change defines a routing front door that keeps authoring on-device whenever possible and only escalates to the service (with explicit confirmation) when a rule genuinely can't be built locally.

The contract introduces:

  • cli-detect — a deterministic, offline taskless detect --json signal scan.
  • cli-rule-routingroute / existing / static / remote recipes with a confidence-gated contract: reason before routing, commit local on reasonable confidence, and treat try-verify-escalate as a failure fallback that prompts-and-confirms before spending a generation.
  • cli-help (modified) — register the four routing topics + intent telemetry.
  • skill-taskless (modified) — reverse named-tool suppression so naming a linter engages routing; the 1024-char description ceiling is a first-class gating constraint.

This change deliberately does not define static-vs-runtime classification — that cut is owned upstream by the Runtime Rules project (TSKL) and lives behind remote. route only decides local-vs-remote.

This is the base of a stack; implementation PRs land on top of it group by group.

Refs TSKL Runtime Rules


Stack generated by Git Town

thecodedrift and others added 2 commits June 11, 2026 16:02
Add the change contract for a local-first rule-routing layer: a
deterministic detect command plus route/existing/static/remote recipes
that keep authoring on-device and gate the login wall behind reasonable
confidence with a confirm-before-service fallback.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add `taskless detect --json`: an offline, deterministic scan of the repo
for configured linters (config files, pyproject tool tables, package
deps), inferred languages/frameworks, and the repo's own rule styles.
No LLM, no network, no auth — it emits stable signal JSON to feed the
routing recipe. Includes a focused scanner module, output schema, and
integration tests covering detection, language/framework inference,
no-packaged-rule-claims, and the offline/no-auth contract.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add the four routing recipes the skill fetches as the rule-authoring
front door. `route` runs detect, requires the agent to write its
rationale before naming a destination, commits local on reasonable
confidence, asks when multiple paths fit, and treats try-verify-escalate
as a failure fallback that prompts-and-confirms before spending a
generation. `existing` authors in a detected linter's dialect (repo-first
knowledge, web fallback, author-only). `static` authors a verified local
ast-grep rule in the canonical on-disk shape, cleaning up an abandoned
candidate on escalation. `remote` collects inputs and delegates to the
rule create backend, letting the service decide static vs runtime.

Recipes are auto-embedded via the existing import.meta.glob step and all
four resolve through `taskless help <topic>`.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Defines a spec-driven OpenSpec contract for a local-first rule-authoring “routing front door” in Taskless, centered around an offline detect signal scan and a help-recipe based classifier (route) that prefers local authoring paths (existing / static) and escalates to the service (remote) only with explicit user confirmation when needed.

Changes:

  • Adds a new OpenSpec change set (local-rule-routing) with proposal/design docs and a spec-driven manifest.
  • Introduces CLI requirements for taskless detect --json and for the route / existing / static / remote help-recipe layer (including rationale-first and confirmation-gated escalation semantics).
  • Updates the skill-taskless contract to engage routing when a linter is named (instead of suppressing) and to route rule-authoring via the new route topic.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 12 comments.

Show a summary per file
File Description
openspec/changes/local-rule-routing/specs/skill-taskless/spec.md Updates the skill triggering and routing contract to use the new routing front door.
openspec/changes/local-rule-routing/specs/cli-rule-routing/spec.md Specifies the routing recipe contract and the three destinations (existing/static/remote).
openspec/changes/local-rule-routing/specs/cli-help/spec.md Requires help-topic registration + telemetry for routing topics.
openspec/changes/local-rule-routing/specs/cli-detect/spec.md Specifies an offline, deterministic detect --json signal scan + stable JSON output requirement.
openspec/changes/local-rule-routing/proposal.md High-level motivation, scope, and impact summary for the change stack.
openspec/changes/local-rule-routing/design.md Detailed design decisions, constraints, and routing rationale/fallback model.
openspec/changes/local-rule-routing/.openspec.yaml Declares the change set as spec-driven with creation date.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread openspec/changes/local-rule-routing/specs/cli-rule-routing/spec.md Outdated
Comment thread openspec/changes/local-rule-routing/specs/cli-rule-routing/spec.md Outdated
Comment thread openspec/changes/local-rule-routing/proposal.md Outdated
Comment thread openspec/changes/local-rule-routing/proposal.md Outdated
Comment thread openspec/changes/local-rule-routing/proposal.md Outdated
Comment thread openspec/changes/local-rule-routing/specs/skill-taskless/spec.md
Comment thread openspec/changes/local-rule-routing/specs/skill-taskless/spec.md Outdated
Comment thread openspec/changes/local-rule-routing/specs/cli-detect/spec.md Outdated
thecodedrift and others added 3 commits June 11, 2026 16:20
List route/existing/static/remote under an "Authoring recipes" section
of the `taskless help` no-arg index so an agent can discover the
rule-authoring front door. The existing help command already emits
help_<topic> intent telemetry generically, so the routing topics inherit
it. Add integration tests for index listing and topic resolution, plus
an in-process test asserting help_route/existing/static/remote capture.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Reverse the named-tool suppression: naming a linter (eslint, ruff, biome,
ast-grep) now ENGAGES the skill's routing flow via `taskless help route`
instead of quieting it. Replace the "Quiet suggestion" section with a
route-through-route body that forbids fetching `rule create` directly and
adds no linter knowledge, and relax the install gate so the `existing`
path (which only reads the repo) is not blocked when `.taskless/` is
absent. Description measures 835/1024 chars. Skill version is build-locked
to the package version, so a minor changeset drives the bump rather than a
hand-edited mismatch.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a labeled request→route calibration dataset for the route recipe
covering both failure directions: over-claim (Taskless grabbing a
packaged/formatter job that should stay `existing`) and over-escalate (a
locally-solvable request wrongly sent to the login-gated service that
should stay `static`), plus genuine `remote` cases. The route decision is
agent-made by following help/route.txt, so the coverage test guards the
dataset's balance across routes and traps rather than running a code
classifier. Closes out the change: openspec validate passes, full CLI
suite green, detect + routing recipes smoke-tested end-to-end.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@thecodedrift
thecodedrift marked this pull request as ready for review June 11, 2026 23:48
thecodedrift and others added 4 commits June 11, 2026 17:04
Resolve Copilot review on PR #23:
- Drop the "provably cannot be built locally" framing in the proposal; it
  set a stricter bar than the confidence-gated contract. Login is suggested
  when route is not reasonably confident a rule is locally solvable, or when
  a confident local attempt fails and the user confirms.
- Tighten the cli-rule-routing spec so routing distinguishes three states:
  confident-local, reasonable-belief-not-local (-> remote), and genuine
  uncertainty (-> ask). Mere uncertainty no longer reads as a remote trigger.
- Reference the canonical `npx @taskless/cli help route` invocation in the
  skill-taskless spec instead of a bare `taskless` binary name.
- Fix Markdown inline-code spans that were split across line breaks.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Reword the cli-detect spec: detect validates its --json output against an
internal Zod schema before printing (same as info/check), rather than a
"published output schema." The schema is an internal contract and detect
exposes no --schema mode. Resolves the remaining Copilot note on PR #23.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a JSON example of `detect --json` output to the route recipe's scan
step, so the agent sees the shape it consumes (linters, languages,
frameworks, ruleStyles) — parity with how info/check recipes show their
--json output. Addresses review feedback on the routing layer.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Tighten route.txt step 3 to match the cli-rule-routing spec: choosing
`remote` requires a positive belief the request cannot be solved locally
(cross-file/semantic), not mere lack of confidence. Genuine uncertainty
routes to a clarifying question, never to a generation-spending remote.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
thecodedrift and others added 14 commits June 11, 2026 17:36
* feat/local-rule-routing:
  docs(openspec): Clarify detect output schema is internal, not published
  docs(openspec): Address review feedback on local-rule-routing contract
* feat/local-rule-detect:
  docs(openspec): Clarify detect output schema is internal, not published
  docs(openspec): Address review feedback on local-rule-routing contract
* feat/local-rule-recipes:
  docs(cli): Align route recipe with the three-state contract
  docs(cli): Show detect output shape in the route recipe
  docs(openspec): Clarify detect output schema is internal, not published
  docs(openspec): Address review feedback on local-rule-routing contract
* feat/local-rule-help:
  docs(cli): Align route recipe with the three-state contract
  docs(cli): Show detect output shape in the route recipe
  docs(openspec): Clarify detect output schema is internal, not published
  docs(openspec): Address review feedback on local-rule-routing contract
* feat/local-rule-skill:
  docs(cli): Align route recipe with the three-state contract
  docs(cli): Show detect output shape in the route recipe
  docs(openspec): Clarify detect output schema is internal, not published
  docs(openspec): Address review feedback on local-rule-routing contract
Address review on PR #24:
- Guard package.json dependency parsing: a malformed field (array/string/
  null) no longer yields bogus dependency names via Object.keys.
- Match pyproject tool tables exactly: `[tool.ruff]` or a nested
  `[tool.ruff.lint]`, never a similarly-prefixed sibling like
  `[tool.ruff-lsp]`. Anchored at line start to avoid value matches.
- Rename the linter `configFiles` output field to `evidence`: it holds
  config paths AND non-path markers (pyproject tables, package deps), so
  the old name/contract was misleading.
- Drop the divergent unused detect errorSchema; the error path emits the
  standard `{ ok, code, message }` envelope via makeErrorEnvelope.
- Run detect tests with telemetry disabled (DO_NOT_TRACK), keeping the
  offline scan path hermetic, and add coverage for the table-prefix and
  malformed-manifest cases.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
PR #25 review:
- remote.txt: stop advertising runtime rules / check.ts as current
  behavior, since runtime-rule support isn't shipped end-to-end yet.
  Reframe the recipe around gathering inputs and delegating to
  `rule create`; the service owns rule-type selection and today writes
  ast-grep rules under .taskless/rules/.
- static.txt: instruct writing the matching `id` field in the test file
  (alongside valid/invalid), as rule create --anonymous and the CLI's
  test-file writer do and ast-grep test filtering expects.
- route.txt: update the detect output example to the renamed `evidence`
  field (follows the detect rename on PR #24).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
PR #27 review:
- The changeset targeted the private, unpublished root `@taskless/skills`
  package, which produces no release and is overwritten by
  sync-skill-versions. Target `@taskless/cli` — the published package and
  the version source of truth that skill metadata.version is locked to.
- Add `stylelint` to the skill body's example tool list so it matches the
  description's list.
- Update the tasks.md 4.3 note to describe the real release mechanism
  (@taskless/cli version drives the skill version via sync-skill-versions).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat/local-rule-detect:
  fix(cli): Harden detect against malformed manifests and false positives
* feat/local-rule-recipes:
  docs(cli): Address review on routing recipes
  fix(cli): Harden detect against malformed manifests and false positives
* feat/local-rule-help:
  docs(cli): Address review on routing recipes
  fix(cli): Harden detect against malformed manifests and false positives
* feat/local-rule-skill:
  fix(skill): Target @taskless/cli in the changeset; align tool lists
  docs(cli): Address review on routing recipes
  fix(cli): Harden detect against malformed manifests and false positives
PR #28 review:
- The trap-coverage test asserted the traps were declared but never
  verified each trap has at least one case, so the dataset could silently
  stop covering a failure direction (e.g. under-engage) while the test
  stayed green. Now every declared trap must have >= 1 case, and
  under-engage cases are asserted to route to `existing`.
- Fix the tasks.md note to point at the real fixture/test paths under
  packages/cli/test/.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
All 25 tasks are complete, so finalize the change on the tip of the
stack: apply the delta specs into the main specs (new cli-detect and
cli-rule-routing capabilities; cli-help and skill-taskless updates) and
move the change to openspec/changes/archive/2026-06-12-local-rule-routing/.
With no unarchived change remaining, the PR OpenSpec Archive Check passes
for the final merged state.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
thecodedrift and others added 28 commits June 13, 2026 20:31
Drop the frameworks field from the detect output example and note the scan
is monorepo-aware (evidence can carry a sub-package path).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Mirror the detect contract changes into the synced cli-detect capability
  spec: drop frameworks, add the languages-only / per-language-manifest /
  monorepo scenarios.
- Add a README testing section clarifying the two kinds of test: the local
  vitest suite (deterministic, no agent) versus the route-honesty dataset,
  whose automated test only guards the fixture structure while the actual
  agent evaluation is a separate manual calibration step.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* feat/local-rule-recipes:
  docs(cli): Update route recipe detect example for the new shape
* feat/local-rule-help:
  docs(cli): Update route recipe detect example for the new shape
* feat/local-rule-skill:
  docs(cli): Update route recipe detect example for the new shape
detect recognized these languages but reported zero linters for them. Fill
the obvious gaps with config-file signals: golangci-lint (Go), Clippy (Rust),
and PHPStan / PHP_CodeSniffer / Psalm (PHP). Still tool-level signal, no rule
catalog — consistent with the D3 non-goal.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* feat/local-rule-detect:
  feat(cli): Add linters for already-detected Go, Rust, and PHP
* feat/local-rule-recipes:
  feat(cli): Add linters for already-detected Go, Rust, and PHP
* feat/local-rule-help:
  feat(cli): Add linters for already-detected Go, Rust, and PHP
* feat/local-rule-skill:
  feat(cli): Add linters for already-detected Go, Rust, and PHP
When the restructure-cli-telemetry change lands, detect/help must conform to
the cli_run + cli_help taxonomy. Mark both sites with a shared
TODO(telemetry-taxonomy) tag: drop the silent cli_detect capture in detect.ts
(the easy-to-miss half) and convert the help_<topic> assertions (which fail on
rebase, so they self-surface).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Reference the tracking issue (#39) from both reconciliation anchors so the
context lives next to the code.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* main: (21 commits)
  refactor(cli): Uppercase the acronym in CLIConfig
  refactor(cli): Uppercase the acronym in CLIErrorEnvelope too
  fix(cli): Carry the CLIErrorCode rename into auth.ts
  docs(openspec): Uppercase CLIError/CLIErrorCode in the change contract
  docs(openspec): Uppercase CLIError/CLIErrorCode in the analytics spec
  refactor(cli): Uppercase the CLI acronym in CliError/CliErrorCode
  docs(openspec): Sync corrected check/help spec into the archived capability
  fix(cli): Resolve cli_run identity at invocation start, not end
  test(cli): Prove help_* removal once via a source scan, not per-test
  test(cli): Assert no legacy help_* event on served-topic and index paths
  refactor(cli): Single-pass check counts; robust cli_installed assertion
  fix(cli): Only emit cli_rule_created/improved when rules are written
  fix(cli): Resolve cli_run identity fresh; tighten cli_error + drop cli_version
  docs(openspec): Address review on the telemetry contract
  ci(openspec): Skip the archive check on non-tip stacked PRs
  chore(openspec): Archive restructure-cli-telemetry and sync specs
  feat(cli): Collapse help_* into cli_help { topic }; drop cli_info
  feat(cli): Concrete auth + lifecycle events; drop start/_completed pairs
  feat(cli): Emit concrete rule events; drop rule start/_completed pairs
  feat(cli): Emit cli_run once per invocation from the runner
  ...
* feat/local-rule-routing: (21 commits)
  refactor(cli): Uppercase the acronym in CLIConfig
  refactor(cli): Uppercase the acronym in CLIErrorEnvelope too
  fix(cli): Carry the CLIErrorCode rename into auth.ts
  docs(openspec): Uppercase CLIError/CLIErrorCode in the change contract
  docs(openspec): Uppercase CLIError/CLIErrorCode in the analytics spec
  refactor(cli): Uppercase the CLI acronym in CliError/CliErrorCode
  docs(openspec): Sync corrected check/help spec into the archived capability
  fix(cli): Resolve cli_run identity at invocation start, not end
  test(cli): Prove help_* removal once via a source scan, not per-test
  test(cli): Assert no legacy help_* event on served-topic and index paths
  refactor(cli): Single-pass check counts; robust cli_installed assertion
  fix(cli): Only emit cli_rule_created/improved when rules are written
  fix(cli): Resolve cli_run identity fresh; tighten cli_error + drop cli_version
  docs(openspec): Address review on the telemetry contract
  ci(openspec): Skip the archive check on non-tip stacked PRs
  chore(openspec): Archive restructure-cli-telemetry and sync specs
  feat(cli): Collapse help_* into cli_help { topic }; drop cli_info
  feat(cli): Concrete auth + lifecycle events; drop start/_completed pairs
  feat(cli): Emit concrete rule events; drop rule start/_completed pairs
  feat(cli): Emit cli_run once per invocation from the runner
  ...
* feat/local-rule-detect: (21 commits)
  refactor(cli): Uppercase the acronym in CLIConfig
  refactor(cli): Uppercase the acronym in CLIErrorEnvelope too
  fix(cli): Carry the CLIErrorCode rename into auth.ts
  docs(openspec): Uppercase CLIError/CLIErrorCode in the change contract
  docs(openspec): Uppercase CLIError/CLIErrorCode in the analytics spec
  refactor(cli): Uppercase the CLI acronym in CliError/CliErrorCode
  docs(openspec): Sync corrected check/help spec into the archived capability
  fix(cli): Resolve cli_run identity at invocation start, not end
  test(cli): Prove help_* removal once via a source scan, not per-test
  test(cli): Assert no legacy help_* event on served-topic and index paths
  refactor(cli): Single-pass check counts; robust cli_installed assertion
  fix(cli): Only emit cli_rule_created/improved when rules are written
  fix(cli): Resolve cli_run identity fresh; tighten cli_error + drop cli_version
  docs(openspec): Address review on the telemetry contract
  ci(openspec): Skip the archive check on non-tip stacked PRs
  chore(openspec): Archive restructure-cli-telemetry and sync specs
  feat(cli): Collapse help_* into cli_help { topic }; drop cli_info
  feat(cli): Concrete auth + lifecycle events; drop start/_completed pairs
  feat(cli): Emit concrete rule events; drop rule start/_completed pairs
  feat(cli): Emit cli_run once per invocation from the runner
  ...
* feat/local-rule-recipes: (21 commits)
  refactor(cli): Uppercase the acronym in CLIConfig
  refactor(cli): Uppercase the acronym in CLIErrorEnvelope too
  fix(cli): Carry the CLIErrorCode rename into auth.ts
  docs(openspec): Uppercase CLIError/CLIErrorCode in the change contract
  docs(openspec): Uppercase CLIError/CLIErrorCode in the analytics spec
  refactor(cli): Uppercase the CLI acronym in CliError/CliErrorCode
  docs(openspec): Sync corrected check/help spec into the archived capability
  fix(cli): Resolve cli_run identity at invocation start, not end
  test(cli): Prove help_* removal once via a source scan, not per-test
  test(cli): Assert no legacy help_* event on served-topic and index paths
  refactor(cli): Single-pass check counts; robust cli_installed assertion
  fix(cli): Only emit cli_rule_created/improved when rules are written
  fix(cli): Resolve cli_run identity fresh; tighten cli_error + drop cli_version
  docs(openspec): Address review on the telemetry contract
  ci(openspec): Skip the archive check on non-tip stacked PRs
  chore(openspec): Archive restructure-cli-telemetry and sync specs
  feat(cli): Collapse help_* into cli_help { topic }; drop cli_info
  feat(cli): Concrete auth + lifecycle events; drop start/_completed pairs
  feat(cli): Emit concrete rule events; drop rule start/_completed pairs
  feat(cli): Emit cli_run once per invocation from the runner
  ...
* feat/local-rule-help: (21 commits)
  refactor(cli): Uppercase the acronym in CLIConfig
  refactor(cli): Uppercase the acronym in CLIErrorEnvelope too
  fix(cli): Carry the CLIErrorCode rename into auth.ts
  docs(openspec): Uppercase CLIError/CLIErrorCode in the change contract
  docs(openspec): Uppercase CLIError/CLIErrorCode in the analytics spec
  refactor(cli): Uppercase the CLI acronym in CliError/CliErrorCode
  docs(openspec): Sync corrected check/help spec into the archived capability
  fix(cli): Resolve cli_run identity at invocation start, not end
  test(cli): Prove help_* removal once via a source scan, not per-test
  test(cli): Assert no legacy help_* event on served-topic and index paths
  refactor(cli): Single-pass check counts; robust cli_installed assertion
  fix(cli): Only emit cli_rule_created/improved when rules are written
  fix(cli): Resolve cli_run identity fresh; tighten cli_error + drop cli_version
  docs(openspec): Address review on the telemetry contract
  ci(openspec): Skip the archive check on non-tip stacked PRs
  chore(openspec): Archive restructure-cli-telemetry and sync specs
  feat(cli): Collapse help_* into cli_help { topic }; drop cli_info
  feat(cli): Concrete auth + lifecycle events; drop start/_completed pairs
  feat(cli): Emit concrete rule events; drop rule start/_completed pairs
  feat(cli): Emit cli_run once per invocation from the runner
  ...
* feat/local-rule-skill: (21 commits)
  refactor(cli): Uppercase the acronym in CLIConfig
  refactor(cli): Uppercase the acronym in CLIErrorEnvelope too
  fix(cli): Carry the CLIErrorCode rename into auth.ts
  docs(openspec): Uppercase CLIError/CLIErrorCode in the change contract
  docs(openspec): Uppercase CLIError/CLIErrorCode in the analytics spec
  refactor(cli): Uppercase the CLI acronym in CliError/CliErrorCode
  docs(openspec): Sync corrected check/help spec into the archived capability
  fix(cli): Resolve cli_run identity at invocation start, not end
  test(cli): Prove help_* removal once via a source scan, not per-test
  test(cli): Assert no legacy help_* event on served-topic and index paths
  refactor(cli): Single-pass check counts; robust cli_installed assertion
  fix(cli): Only emit cli_rule_created/improved when rules are written
  fix(cli): Resolve cli_run identity fresh; tighten cli_error + drop cli_version
  docs(openspec): Address review on the telemetry contract
  ci(openspec): Skip the archive check on non-tip stacked PRs
  chore(openspec): Archive restructure-cli-telemetry and sync specs
  feat(cli): Collapse help_* into cli_help { topic }; drop cli_info
  feat(cli): Concrete auth + lifecycle events; drop start/_completed pairs
  feat(cli): Emit concrete rule events; drop rule start/_completed pairs
  feat(cli): Emit cli_run once per invocation from the runner
  ...
The telemetry restructure has landed on main, so the detect stack now adopts
the new event taxonomy:

- detect.ts: drop the bespoke cli_detect capture. detect is read-only, so the
  per-invocation cli_run denominator (from the runner) covers it. Removes the
  now-unused getTelemetry import.
- help-routing-telemetry.test.ts: the per-topic help_<topic> events collapsed
  into cli_help { topic }; assert cli_help for the routing topics.

Clears both TODO(#39) anchors. Closes #39.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Conform detect.ts to the cli_ taxonomy now on main: detect is read-only and
rides on cli_run, so the bespoke cli_detect capture and its getTelemetry import
go. Matches the tip's #39 resolution so the branch is green/consistent.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
help.ts now emits cli_help { topic } instead of per-topic help_<topic> (the
taxonomy on main). Update the routing-topic assertions to match so this branch
is green/consistent with the tip's #39 resolution.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* feat/local-rule-detect:
  chore(cli): Drop cli_detect on the detect branch (telemetry taxonomy)
* feat/local-rule-recipes:
  chore(cli): Drop cli_detect on the detect branch (telemetry taxonomy)
* feat/local-rule-help:
  test(cli): Assert cli_help for routing topics (telemetry taxonomy)
  chore(cli): Drop cli_detect on the detect branch (telemetry taxonomy)
* feat/local-rule-skill:
  test(cli): Assert cli_help for routing topics (telemetry taxonomy)
  chore(cli): Drop cli_detect on the detect branch (telemetry taxonomy)
feat(cli): Add deterministic detect command for rule routing
@thecodedrift
thecodedrift merged commit 9792db4 into main Jun 15, 2026
3 checks passed
@thecodedrift
thecodedrift deleted the feat/local-rule-routing branch June 15, 2026 01:23
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.

2 participants