Status: partially shipped · fact-checked 2026-05-18. Slices 1-4 are implemented in-tree:
audit --format sarif,query --ci,audit --ci, rootaction.yml, package-manager detection,codemap pr-comment, and non-blocking CI dogfood all exist. Open work is now Slice 5:MARKETPLACE.md,v1.0.0/ floatingv1tags, Marketplace listing setup, external smoke, and hardeningaction-smokeafter publish.Motivator: GitHub Marketplace is the dominant discovery + adoption surface for tools in the codebase-intelligence cohort, and codemap is currently absent from it. The in-repo Action closes the CI wrapper gap once it is tagged and listed; until then consumers can use the CLI surfaces directly or a local-path action ref.
Tier: M effort. Wraps existing CLI surface; no schema changes, no new engines, no new transports. Only new substrate is the optional PR-comment writer (~one TS module).
These are committed to v1. Questions opened against them must justify against the linked decisions.
| # | Decision | Source |
|---|---|---|
| L.1 | Composite action, not Docker. Reuses host runner's Node + caches; faster cold-start; no image registry to maintain. | GitHub Actions best practice for npm-distributed CLIs |
| L.2 | Action repo lives at stainless-code/codemap, published under the same git tag (@v1, @v1.2.3). No codemap-action split repo. (Q-B grill: split-repo's drift risk is asymmetric — codemap-action@vN pinned against codemap-cli@vM can hit a removed flag and fail silently in CI; same-repo prevents this by construction.) |
Marketplace allows publishing from any repo path; same-repo keeps action.yml in lockstep with CLI behaviour |
| L.3 | Moat-A clean — every Action output is a query --recipe <id> or audit --base <ref> rendering through --format sarif / --format annotations / JSON. No verdict-shaped primitives in the Action. |
Moat A |
| L.4 | No telemetry hook in the Action. No usage pings, no failure callhome. Logs stay on the runner. | Floor "No telemetry upload" |
| L.5 | No mutation of repo state by default — the Action runs read-side codemap verbs (audit, query --recipe, --format sarif/annotations). Optional PR-comment writer is opt-in. |
Floor "No fix engine" |
| L.6 | --ci aggregate flag + --format sarif on audit are in scope and shipped. --ci exists on query AND audit (the two finding-producing verbs); aliases --format sarif + non-zero exit-on-issue (query: any row; audit: delta additions). query --ci only also suppresses the no-locatable-rows stderr warning. --no-watch is not wrapped — only mcp/serve have a watcher; meaningless on query/audit. |
Pure CLI surface; cheap; lifts the Action wrapper from ~12 commands to one |
| L.7 | Audit verdict + thresholds stay deferred. Action ships with raw deltas + SARIF; the verdict-config trigger (two consumers shipping jq thresholds) gates promotion. |
roadmap.md § Backlog audit-verdict item — Action shipping is itself a likely accelerant for the trigger |
These are the design questions the plan-PR resolves before impl starts. Each gets a "Resolution" subsection below as it crystallises.
-
Q1 —
action.ymlinput surface. Three shapes considered: minimum viable (~7 inputs,command:as the universal escape hatch), phased rollout (7 → 12 → 16 across v1.0 / v1.1 / v1.2), and ideal day-one (~16 declarative inputs).Resolution (Q-B grill): ship the ideal day-one — ~16 declarative inputs in v1.0. Reasoning: consumers in this Actions cohort (
actions/setup-node,actions/upload-artifact,oven-sh/setup-bun, …) expect 10-15-input density and reach for declarative inputs over shell-string composition; structured inputs compose cleanly with${{ }}interpolation and surface in IDE autocomplete; "usecommand:for everything non-trivial" pushes consumers into shell-string forking that's worse for both ergonomics and our listing's example matrix.v1.0 input list (~16):
inputs: # WHERE TO RUN working-directory: # monorepo subdir (default: .) package-manager: # autodetect override: npm | pnpm | yarn | bun version: # pin CLI version; empty = project devDep → latest fallback state-dir: # override `.codemap/` location # WHAT TO RUN — high-level (mutually exclusive; precedence: command > mode > defaults) mode: # audit | recipe | aggregate | command (default: audit) recipe: # recipe id (when mode=recipe) params: # multiline key=value (when mode=recipe) baseline: # saved baseline name (when mode=recipe) audit-base: # git ref (default: ${{ github.base_ref }} on pull_request events) changed-since: # filter to files changed since ref group-by: # owner | directory | package command: # raw CLI args (escape hatch; precedence over all above) # WHAT TO DO WITH OUTPUT format: # sarif | json | annotations | mermaid | diff (default: sarif) output-path: # default: codemap.sarif upload-sarif: # default: true (skip if no GHAS) pr-comment: # default: false (per Q4) fail-on: # any | error | warning | never (default: any) token: # default: ${{ github.token }}
Validation rules (action's pre-step):
- Precedence:
command>mode> defaults. Ifcommandis set, allmode/recipe/params/baseline/audit-base/changed-since/group-byinputs are ignored with a single warning log line. mode: reciperequiresrecipe; missing → hard error.mode: auditignoresrecipe/params/baseline(warning); requiresaudit-base(defaults from PR event context, see Q5 resolution).mode: aggregateis deferred to v1.x —action.ymlrejects it today (see Q5 resolution).- Mutually-exclusive combos that don't compose (e.g.
baseline+audit-base) → hard error with a remediation hint pointing at thecommand:escape hatch.
Ripples:
- Q6 aggregate mode deferred to v1.x (supersedes earlier v1.0-blocker note). Q5 reserved γ until multi-recipe SARIF composition is proven;
action.ymlrejectsmode: aggregatewith a v1.x message. - v1.x input additions likely concentrate on edge cases the v1.0 16 don't cover (e.g.
min-severity,recipes-dir,fts5). Promotion bar: ≥2 consumer requests with concrete shapes.
- Precedence:
-
Q2 — Package-manager autodetection. Detect
pnpm-lock.yaml/bun.lock/yarn.lock/package-lock.jsonto pick the install command, OR require an explicitpackage-manager: npm|pnpm|yarn|buninput.Resolution: delegate to
package-manager-detector(antfu/userquin, MIT, 0 deps, 23 kB) via a tinyscripts/detect-pm.mjswrapper invoked fromaction.yml's composite steps. The library implements the equivalent priority ladder we'd hand-roll (lockfile →packageManagerfield →devEngines.packageManagerfield → install-metadata → walk-up to parent dir) plus two cases we'd otherwise miss: install-metadata (the most reliable signal when present) anddevEngines.packageManager. Walk-up support is built in, which solves the monorepo subdir case.Wrapper sketch (action's pre-step):
import { detect } from "package-manager-detector/detect"; import { resolveCommand } from "package-manager-detector/commands"; import { appendFileSync } from "node:fs"; const pm = await detect(); const agent = pm?.agent ?? "npm"; // resolveCommand handles `npm exec` vs `pnpm exec` vs `bun x` vs `yarn dlx` — Q3 lookup-table for free // Write to GITHUB_OUTPUT env file (`::set-output` deprecated since 2022-10). appendFileSync(process.env.GITHUB_OUTPUT, `agent=${agent}\n`);
Precedence:
package-manager:input still wins when set (overrides detection). When unset, the library's default strategy order applies. Multiple-lockfile case is handled by the library; we surface its result + log a warning if ambiguous.Rejected alternatives: hand-rolled bash detection (~30 lines, misses
install-metadata+devEngines.packageManager); explicit-only (friction); try-each-fallback (slow — cascading failed installs); corepack-only (silently fails whenpackageManagerfield absent).Cost: one runtime dependency. Mitigated by 0 transitive deps + 23 kB + antfu maintenance + the alternative being a 30-line bash detection ladder we'd debug forever. Need
actions/setup-node(or runner-preinstalled Node) to execute the detection script — most workflows already have this; if missing, the action adds it as an implicit pre-step. -
Q3 — Where to invoke the CLI.
bun x codemapif Bun is on the runner?npx codemap? Local-install viapackage.jsonis the dominant path (codemap is adevDependencyfor most consumers).Resolution: project-installed first, download-and-execute fallback. Maps directly onto
package-manager-detector's tworesolveCommandintents —'execute-local'(already installed) vs'execute'(download and run). No hand-rolled per-agent branching; the library resolvesnpx/bunx/pnpm dlx/yarn dlxitself.if version-input is set: intent = 'execute' # forced download with pinned version cli = resolveCommand(agent, 'execute', ['@stainless-code/codemap@<version>']) elif codemap in devDependencies: intent = 'execute-local' # consumer's install step already brought codemap in cli = resolveCommand(agent, 'execute-local', ['codemap']) else: intent = 'execute' # not installed; pull latest cli = resolveCommand(agent, 'execute', ['@stainless-code/codemap@latest'])Reasoning: matches consumer's pinned version by default (no surprise drift between local dev and CI); project-local recipes (
<state-dir>/recipes/; default.codemap/recipes/) work for free; faster on cached runners (node_modules/.bin/codemapalready there post-npm ci).version:input forces a pinned'execute'when set — explicit override stays clean. Rejected execute-only (ignores consumer's pinned version), project-only (friction for trial-run), pinned-first inversion (the strongest signal is "what runs locally", which ispackage.json#devDependencies).Edge cases:
- Version mismatch warning. If
version:input is set ANDcodemapis indevDependenciesAND they disagree → log a warning ("Action input version=X differs from project devDependency Y; using input"). Don't error — consumer may be deliberately overriding. bun src/index.tsfor codemap-itself dogfood (Slice 4). This repo's CI calls codemap pre-build. Usecommand:override pointing atbun src/index.ts ...rather than the published binary. Slice 4 documents this as the known special case.
- Version mismatch warning. If
-
Q4 — PR-comment writer scope. Three escalating shapes:
- (a) None — Action emits SARIF only; users wire their own comment-writer Action downstream. Smallest surface; ships v1 fastest.
- (b) Summary comment only — single PR comment with collapsible sections per recipe (rendered from
audit --jsonorquery --recipe X --format json). Closes the dominant "what changed in this PR?" review use case. - (c) Inline review comments — per-row comments on changed lines with
actionstemplate hint. Closes the rest; needs careful rate-limiting (max-commentscap is mandatory).
Resolution (Q-A grill): ship (b) Summary comment in v1.0; (c) Inline review comments deferred to v1.x with a concrete demand trigger (any one of: a consumer asks with a concrete shape, a bot-host integration like CodeRabbit/Copilot/Cursor-bot requests structured PR-comment seeding, or audit-verdict + thresholds ship and the verdict line wants per-line surfacing). The v1.0 summary comment matters most in the cases SARIF→Code-Scanning doesn't cover well: private repos without GHAS (Code Scanning unavailable), repos that haven't enabled Code Scanning, aggregate
audit --base <ref>deltas that lack afile:lineanchor, trend / delta narratives ("coverage 87 % → 84 %"), and bot-context seeding (review bots read PR conversation, not workflow artifacts). v1.0 default for the comment toggle is opt-in (pr-comment: trueAction input) so consumers who already have Code Scanning don't get duplicated surfaces. Toggle defaults flip later if usage shows the comment is the universally expected surface. -
Q5 — Default command for the Action. What does
- uses: stainless-code/codemap@v1with zero inputs do?- Option α:
codemap audit --base ${{ github.base_ref }} --format sarif— one-shot structural-drift on every PR, SARIF uploaded to Code Scanning. - Option β:
codemap query --recipe deprecated-symbols --format sarif(or another single recipe) — narrower, less surprising. - Option γ: aggregate run —
audit+ a curated set of recipes (untested-and-dead,boundary-violations,deprecated-symbols) — broader coverage but more opinionated. - Option δ: bare
codemap --ci, project config decides — pushes opinion to consumers; needs new config schema.
Resolution (Q-B grill): α + skip-on-non-PR. On
pull_requestevents the Action runscodemap audit --base ${{ github.base_ref }} --ci(SARIF + non-zero exit on additions). On any other event (push,schedule,workflow_dispatch, …) the Action no-ops withecho "codemap action: no PR context, skipping"and exits 0 — there's no meaningful default without a base ref, and firing β-style opinionated recipes on push events surfaces findings consumers didn't ask for. β is a worse α (no PR-scoped diff). γ is reserved until multi-recipe SARIF composition is proven; currentaction.ymlrejectsmode: aggregatewith a v1.x message. δ over-engineers a config concept that doesn't exist. Consumers wanting push-event runs pass an explicitcommand:input. - Option α:
-
Q6 — SARIF rule.id taxonomy under
mode: aggregate. (Deferred to v1.x — superseded Q1 ripple that promoted this to a v1.0 blocker.) Single-recipe--format sarifis shipped (rule.id = codemap.<recipe-id>). Aggregate runs (multiple recipes in one Action invocation) need a stable convention for combining results — likely concat-into-one-sarif-file with rule definitions de-duplicated byrecipe-id(each rule appears once intool.driver.rules[]; each finding'sruleIdmatches). Verify in GitHub Code Scanning before enablingmode: aggregate; fall back to one-SARIF-per-recipe withcategory:if dedup misbehaves. -
Q7 — Versioning +
@v1tag strategy. Convention: floating@v1major tag updated on every minor/patch release;@v1.2.3for pin-to-exact.action.ymllives at repo root;dist/is not required for composite actions (only for JS actions).Resolution: floating major
@v1+ changesets-driven release. Cohort norm (actions/checkout@v4,actions/setup-node@v4,oven-sh/setup-bun@v2, …); Renovate/Dependabot-friendly (major tags are the unit they bump on); enforces semver discipline (any input/output break is a v2 bump, never within v1.x).Release workflow (concrete; piggybacks on existing changesets pipeline):
- PR adds a changeset → merge to
mainbumpspackage.jsonversion via the existing release pipeline. - Release workflow on
main:- Push exact tag
v1.2.3at the merge commit. - Force-update
v1floating tag to the same commit (git tag -f v1 <sha> && git push --force origin v1). - npm publish (already in pipeline).
- Marketplace auto-syncs from the same tag — no separate publish step needed once the listing exists.
- Push exact tag
- Major bump (v1.x.y → v2.0.0): create new
v2floating tag at the breaking-change commit;v1stops moving (consumers on@v1continue receiving v1.x.y patches if backports happen, otherwise frozen).
Backwards-compat discipline within v1: floating
@v1requires never breaking inputs/outputs in v1.x. New behaviors land as opt-in inputs (e.g. v1.0 shipspr-comment: falsedefault; v1.5 may flip default but never removes the input).Safety checks:
- Tag force-push must be allowed for
v1. Branch protection rules in this repo currently apply to branches, not tags — verify before Slice 5. - Tag signing — sign exact tags (
v1.2.3) viagpg; floatingv1inherits no signature (it's a pointer, not a release tag). GitHub treats both as the source of truth for@v1resolution. - Single major supported — small-team policy. Document explicitly that backports to old majors aren't promised; consumers on
@v1after@v2ships are responsible for migration when they want new behavior.
Action version stream is independent of CLI version stream. The CLI/npm version is driven by
package.json; the Action publishes at its ownv1.0.0regardless. Marketplace tags are per-repo; the Action'sv1floating tag and the CLI's npm versions occupy different namespaces and don't conflict. (Fact-check 2026-05: original draft asserted "codemap CLI is already 1.x" — that was wrong. Decoupled version streams is actually the right shape: CLI semver tracks core engine stability; Action semver tracks the wrapper-input contract. They evolve independently.)Rejected: minor-floating (
@v1.2) — breaks Renovate/Dependabot conventions; exact-pin only — staleness without auto-bumping; branch-based (@main) — cohort rejects, too risky for CI. - PR adds a changeset → merge to
-
Q8 — How does the Action run in private repos / monorepos? Default
working-directory: .works for single-package repos. For monorepos, exposeworking-directoryinput. CODEOWNERS-driven--group-by owneris already shipped — Action should pass through.Resolution: covered by earlier resolutions, no new substrate needed. Monorepo case →
working-directoryinput (already in the v1.0 input list per Q1). Private-repo case → identical Action runtime; only differentiator is SARIF→Code-Scanning requires GitHub Advanced Security for private repos, which is the v1.0 motivation for thepr-commentwriter existing (per Q4). CODEOWNERS-driven--group-by ownerflows throughcommand:or the v1.0group-by:input. -
Q9 — Codemap-itself's existing CI. This repo's
.github/workflows/ci.ymlruns golden / benchmark / typecheck / lint. The Action would dogfood codemap on its own PRs (eat your own dogfood). Slice 4 wires this; verifies the Action against a real repo before publishing.Resolution: Slice 4 wires it via
command:override pointing atbun src/index.ts ...rather than the published binary (codemap-itself runs from source pre-build) — already documented as the known special case in the Q3 resolution. No additional design substrate; Slice 4 is execution. -
Q10 — Marketplace listing metadata. Branding (icon + colour), description, tags (
code-quality,static-analysis,ai-agents?), README rendered on the listing. Cosmetic but important for discovery. Defer to Slice 5 (publishing).Resolution: defer to Slice 5 with a fixed checklist so the cosmetic decisions don't drag:
- Icon: reuse the existing codemap brand asset if one exists; otherwise pick during Slice 5.
- Colour: GitHub Marketplace's brand-colour palette.
- Tags:
code-quality,static-analysis,code-search,code-intelligence. Avoidlinter— codemap is Moat-A "no opinionated rule engine";linterframing miscategorises the tool. - Description (≤150 chars per Marketplace constraint): "SQL-queryable structural index of your codebase. Run any predicate as a recipe; CI gating via SARIF → Code Scanning."
- README: point Marketplace at an action-focused
MARKETPLACE.mdrather than the codemap-CLI rootREADME.md— keeps the listing copy tight and action-shaped. - Discipline: listing copy must respect
plan-pr-inspiration-discipline(no peer-tool comparisons in the listing) and align withdocs/why-codemap.mdpositioning.
Each open decision gets a "Resolution" subsection below as it crystallises (mirrors the c9-plan and research-note pattern).
Four pieces; the last two are genuinely new substrate:
action.ymlat repo root — composite action declaring inputs (Q1), steps (detect package manager → install codemap → run command → upload SARIF). Pure declarative wrapper.--format sarifonaudit— shipped incmd-audit.ts, routing audit deltas throughoutput-formatters.tsas SARIF.--ciaggregate flag incmd-query.tsandcmd-audit.ts— shipped as an alias for--format sarif+ non-zero exit-on-issue (query --cialso suppresses the no-locatable-rows stderr warning;audit --cidoes not).- PR-comment writer (Q4 (b), Slice 3) — shipped as
src/cli/cmd-pr-comment.ts, reading SARIF / audit JSON and rendering a markdown summary for the Action's optional PR-comment step.
No schema changes. No new transports. The Action consumes existing engines.
Sharpens (user-facing):
- Discovery — Marketplace listing is the dominant top-of-funnel for codebase-intelligence tools; codemap's npm-only adoption path leaves that funnel empty.
- Adoption friction —
- uses: stainless-code/codemap@v1is a single-line CI integration. Today's path is "write a workflow that runscodemap audit --base ${{ github.base_ref }} --json, transform JSON to SARIF, then upload the artifact" — a five-step recipe most teams don't write. - PR-review feedback loop — SARIF surfaces in Code Scanning; annotations show inline; (Q4 (b)) summary comment lands in the PR conversation. Closes the "I ran codemap locally but it never reaches the reviewer" gap.
Does NOT sharpen:
- Agent UX directly — agents call MCP / CLI, not Actions. Indirect lift only: the Action seeds CodeRabbit / Copilot / Cursor-bot reviews with codemap's structural facts, which they then cite — but that's downstream of the Action's primary value.
- Audit verdict semantics — Action ships raw deltas + SARIF; pass/warn/fail thresholds remain backlog (per L.7). Shipping the Action is itself the most likely accelerant for the trigger fire (real consumers writing
jqthreshold scripts). - Recipe authoring — Action consumes recipes, doesn't grow them. Project-local recipes (
<state-dir>/recipes/; default.codemap/recipes/) work in CI exactly as locally; no Action-specific surface. - IDE integration — that's
(d) LSP plan's scope; sibling plan, see relationship below.
lsp-diagnostic-push.md is the sibling plan that renders the same recipe substrate to a different consumer surface (IDE squigglies via VSCode extension + Open VSX, vs CI surfaces via GitHub Marketplace). Both plans are intentional separate scopes:
- Same Moat-A discipline on both: every output is a recipe rendering through
--format <X>. Reviewer test ("is this finding queryable viaquery --recipe X?") is identical. - Same recipe set rendered (
untested-and-dead,unimported-exports,boundary-violations,high-complexity-untested,deprecated-symbols,components-touching-deprecated). - Different formatter — Action ships
--format sarifonaudit(Slice 1a); LSP ships--format lsp-diagnostic. Both extendoutput-formatters.tsthe same way; the Action's audit-SARIF shape decisions (delta-row → SARIFresultmapping) are precedent the LSP plan can mirror. - Sequential, not blocking either way. Action ships first (M effort, no monorepo conversion needed —
action.ymlis a single root file). LSP ships last (XL effort, may force the repo-structure decision perlsp-diagnostic-push.md § Repo-structure tradeoffs). Neither blocks the other. - Disjoint user populations — Marketplace Action seeds CI users; VSCode extension seeds IDE users. The Action's listing copy can cross-link to the LSP extension once both ship, but neither requires the other.
Per tracer-bullets — ship one vertical slice end-to-end before expanding.
v1.0 scope (Q-A grill resolution — i-full): all five slices land in v1.0. Inline review comments (Q4 (c)) are the only v1.x deferral; the summary comment (Q4 (b)) ships in v1.0 because the cases SARIF→Code-Scanning doesn't cover (private repos without GHAS, aggregate audit deltas, bot-context seeding) are present from day one and waiting for a demand signal would slow learning.
- Slice 1:
--format sarifonaudit+--ciaggregate flag onqueryandaudit— shipped. Steps:- 1a. Extend
cmd-audit.tsparser to accept--format sarif(and route throughoutput-formatters.ts). Decide SARIF shape for delta-rows: eachaddedrow → SARIFresultwithruleIdlikecodemap.audit.files-added/codemap.audit.dependencies-added/codemap.audit.deprecated-added; severity =warning;locations[]fromfile_pathwhen available, omitted for aggregate-count rows. Newaudit-engineintegration withoutput-formatters.ts. Test: golden-scenario SARIF output for a fixture audit. - 1b. Add
--ciflag to bothcmd-query.tsandcmd-audit.ts. Aliases--format sarif+process.exitCode = 1if any rows/deltas (query --cialso suppresses no-locatable-rows stderr). Test:bun src/index.ts query --recipe deprecated-symbols --ciandbun src/index.ts audit --base origin/main --ciboth produce SARIF + non-zero exit when findings exist. - No Action yet — Slice 1 verifies the CLI surfaces the Action will wrap. Independently useful: any non-Action CI consumer benefits from
--ciimmediately.
- 1a. Extend
- Slice 2:
action.ymlminimum — shipped. Rootaction.ymlincludes the composite wrapper, package-manager detection, CLI resolution, SARIF upload, and mode/command input validation. - Slice 3: PR-comment writer (Q4 (b) summary only) — shipped.
src/cli/cmd-pr-comment.tstakes SARIF or audit JSON, emits markdown summary, and the Action's optional final step posts it viagh pr comment. - Slice 4: dogfood on this repo — shipped, non-blocking.
.github/workflows/ci.ymlruns the local-path Action withcommand: --version; it remainscontinue-on-erroruntil the publishedv1tag exists. - Slice 5: publish + Marketplace listing — open. Tag
v1.0.0, push fast-forward@v1, addMARKETPLACE.md, fill listing metadata (icon, description, tags), verify discoverability, then harden Action smoke and update consumer-facing docs. Detailed runbook below.
Slices 1-4 are in-tree; Slice 5 is a sequenced manual runbook that requires a merged commit + access to the Marketplace publishing UI.
Pre-condition: CLI / Action version stream decoupling (per Q7). The Action's @v1 and the CLI's npm version live in separate namespaces — Action publishes at v1.0.0 independent of CLI version. The Action's default invocation does <pm> dlx @stainless-code/codemap@latest, so the CLI just needs the shipped --format sarif (audit) + --ci flags available on npm. CLI v1.0.0 is not required for Action v1.0.0.
Steps:
-
Confirm the current npm release contains the Action-required CLI surfaces.
-
Changesets release workflow on
mainruns automatically for any needed CLI/package bump. -
From the merge commit, tag git
v1.0.0:git tag -a v1.0.0 -m "GitHub Marketplace Action v1" git push origin v1.0.0 -
Force-push the floating
v1tag to the same commit:git tag -f v1 v1.0.0 git push --force origin v1
-
One-time Marketplace listing setup (per Q10 checklist):
- Pick icon (reuse codemap brand asset if exists; else pick during this step).
- Brand colour: GitHub Marketplace palette.
- Tags:
code-quality,static-analysis,code-search,code-intelligence. Avoidlinter(Moat-A "no opinionated rule engine"). - Description (≤150 chars per Marketplace constraint): "SQL-queryable structural index of your codebase. Run any predicate as a recipe; CI gating via SARIF → Code Scanning."
- README: point Marketplace at
MARKETPLACE.md(action-focused) rather than the codemap-CLI root README. AuthorMARKETPLACE.mdin this step if it doesn't exist. - Discipline: listing copy respects
plan-pr-inspiration-discipline(no peer-tool comparisons in the listing) + aligns withdocs/why-codemap.md.
-
Smoke-test on a sacrificial public repo:
- uses: stainless-code/codemap@v1in.github/workflows/; trigger a PR; verify SARIF surfaces in Code Scanning. -
Follow-up PR (post-publish):
- Update
README.md § CIto lead with the Action. - Flip
action-smokeCI job fromcontinue-on-error: trueto a hard gate (Action now publishes a v1 with the right CLI flags, so the smoke meaningfully validates them). - Per
docs/README.mdRule 3, deletedocs/plans/github-marketplace-action.md. Durable design decisions already live in:docs/architecture.md§ "PR-comment wiring" + § "Audit wiring" + § "Output formatters" (CLI + engine seams)docs/glossary.md(--ci+pr-commententries).agents/rules/codemap.md+templates/agents/rules/codemap.md(agent surface)MARKETPLACE.md(consumer-facing)
- Remove the GitHub Marketplace Action backlog entry from
roadmap.mdper Rule 2.
- Update
Subsequent releases: changesets-driven (existing pipeline). On every merge to main that bumps package.json:
- Tag
v<major>.<minor>.<patch>at the merge commit. - Force-push
v<major>floating tag to the same commit (git tag -f v<major> <sha> && git push --force origin v<major>). - npm publish runs automatically.
- Marketplace auto-syncs from the same git tag — no separate publish step.
Major bump (v1.x.y → v2.0.0): create a new v2 floating tag at the breaking-change commit; v1 stops moving. Backports to v1.x.y are not promised (single-major-supported policy per Q7).
- Unit:
--ciflag handling + PR-comment renderer —*.test.tsper touched file. - Integration (CLI): golden scenario for
--ci(existing query-golden harness). - Integration (Action): GitHub workflow on this repo runs the Action against a small fixture-repo branch; assertions on SARIF output + comment text via
ghAPI. Equivalent to the e2e test inaudit-engine.test.tsbut for the Action wrapper. - Marketplace listing — manual verification post-publish (icon renders, install copy works, tags are searchable).
| Item | Mitigation |
|---|---|
| Non-goal: verdict-shaped Action output (pass/warn/fail). | Per L.3 / L.7; ships raw deltas + SARIF. Promotion gated on backlog audit-verdict trigger. |
| Non-goal: mutating repo state from CI. | Per L.5; PR-comment writer is opt-in. No codemap fix (we don't ship one — see Floor "No fix engine"). |
| Non-goal: Docker-image action. | Per L.1; composite only. Slower runners + image-registry maintenance not worth the marginal portability gain. |
| Risk: Action wrapper calls a CLI flag the CLI no longer has. | Per L.2 same-repo publishing — action.yml and CLI live in the same git tag, so an Action change requiring a CLI flag lands in the same PR that adds the flag. Cross-version drift is structurally prevented (the failure mode of split-repo publishing). Note: Action version stream stays independent of CLI version stream per Q7 — @v1 floats forward; CLI follows its own 0.x.y cadence. |
Risk: SARIF rule.id collision under --ci aggregate (Q6). |
Slice 1 verifies single-recipe SARIF passes Code Scanning; Slice 2 / 3 verify multi-recipe aggregation. Defer aggregate to v1.1 if Code Scanning rejects the shape. |
| Risk: PR-comment writer rate-limits / over-posts (Q4 (c) future). | v1 ships summary only (Q4 (b)); inline-review comments deferred until demand signal. max-comments cap mandatory before (c) ships. |
| Risk: Marketplace listing rejected. | Read GitHub's Marketplace publishing docs before Slice 5; Slice 4 dogfooding catches breakage before publish. Composite actions for npm-distributed CLIs are a well-trodden Marketplace path — no structural blocker. |
| Risk: plan abandoned mid-iteration. | Per docs/README.md Rule 8, close as Status: Rejected (YYYY-MM-DD) — <reason>. --ci flag (Slice 1) is independently useful even if Action publishing slips. |
docs/roadmap.md § Backlog— backlog entry + audit-verdict trigger that this Action's adoption is likely to fire.docs/plans/lsp-diagnostic-push.md— sibling plan rendering same recipe substrate to IDE / VSCode surface; complementary, not competitive (see "Relationship to (d) LSP plan" section above).docs/README.mdRule 3 — plan-file convention (this file's location).docs/README.mdRule 8 — closing-state lifecycle if abandoned.docs/README.mdRule 10 — agent rule + skill lockstep update (Slice 5)..agents/rules/tracer-bullets.md— slice cadence.