Skip to content

Expand curated packs, task recipes, and discovery commands - #1

Merged
IMisbahk merged 2 commits into
mainfrom
cursor/expand-capability-surface-5750
Aug 13, 2026
Merged

Expand curated packs, task recipes, and discovery commands#1
IMisbahk merged 2 commits into
mainfrom
cursor/expand-capability-surface-5750

Conversation

@IMisbahk

Copy link
Copy Markdown
Owner

Why

mstack users working across domains needed more than a thin starter catalog: most packs shipped a single specialist and no recipes, discovery could not filter or recommend, and missing toolchains failed as generic spawn errors. This change gives those users a broader, still opt-in capability surface without hosting inference or weakening argv-only execution.

What changed

  • Expanded all 10 starter packs with additional specialists, skills, invokable prompts, and policy-gated task recipes.
  • Added backend-api, qa-testing, observability, and documentation packs.
  • Added mstack pack recommend (read-only evidence from well-known markers; does not install).
  • Added mstack catalog --query and mstack task list --pack/--risk.
  • Enforce file preconditions and report missing executables as step failures (exit 127).
  • Compose selected packs with first-id-wins merging so core resource ids cannot be overwritten.
  • Show selected packs in mstack status.
  • Added worked examples: FieldNote (mobile), SignalWell (data), RepoLens (CLI), DockSense (firmware).

Reasoning

The default Build Like This runtime stays lightweight. Domain depth stays behind explicit pack selection. Recommendation cites files instead of auto-installing, which preserves consent and avoids pretending heuristics are product evidence. Task recipes remain literal argv with shell: false; no deploy, publish, or shell-script recipes were added.

Verification

  • pnpm --filter @imisbahk/mstack test — 45 passed
  • pnpm --filter @mstack/ai-integrations test — 35 passed, 2 skipped (Codex/OpenCode CLIs absent)
  • pnpm typecheck — passed
  • pnpm --filter @imisbahk/mstack build — passed
  • pnpm --filter @imisbahk/mstack docs:generate — regenerated command reference
  • Kept current shipped behavior separate from planned orchestration (mstack agent remains discovery-only)

Scope

Non-goals: marketplace/remote packs, hosted model execution, new AI runtime adapters, packaging/publishing/deployment recipes, and automatic pack installation from heuristics.

Open in Web Open in Cursor 

cursoragent and others added 2 commits August 13, 2026 18:27
Add four documentation-only examples (FieldNote, SignalWell, RepoLens,
DockSense) that show product and architecture decisions for platform
permissions, data contracts, CLI stability, and firmware fail-safes.

Co-authored-by: Misbah K. <m.misbahkhursheed@gmail.com>
Fill every domain pack with specialists, skills, prompts, and argv-only
recipes, and add backend-api, qa-testing, observability, and documentation
packs. Recommend packs from repository evidence without installing them,
filter catalog and task lists, and fail missing preconditions or executables
before a recipe continues.

Co-authored-by: Misbah K. <m.misbahkhursheed@gmail.com>
@IMisbahk

Copy link
Copy Markdown
Owner Author

@cursoragent review

@cursor

cursor Bot commented Aug 13, 2026

Copy link
Copy Markdown

Review is on PR #1. The pack model is sound; the problems are risk labels and contracts on new recipes.

Fix before merge

  1. ml.compileall is read-only but writes __pycache__. Default balanced policy runs it with no confirmation. Same cache issue for ml.mypy.
  2. docs.grep-todo fails when there are no TODOsgit grep exits 1 on no matches; the runner treats that as a failed step.
  3. Catalog detail changed meaning at schemaVersion: 1. Task detail used to be the bare risk class; prompts used to be the argument hint.
  4. Recommend and recipes disagree. compose.yml / terraform/main.tf / docs/ get suggested, then the matching task misses its precondition. confidence: "low" is never produced. Every mstack init repo has docs/, so documentation is always suggested.
  5. New recipes that execute project code (node --test, Playwright, ESLint) are labeled read-only. That copies the old quality.test pattern; new recipes should not.

Pre-existing (not this diff, still worth knowing)

  • Live --json task runs inherit child stdout, so the JSON is not parseable; failed JSON runs exit 0.
  • Timeouts only SIGTERM and can hang.
  • Unknown taskPolicy in project config fails open.

Line comments are on the PR. I can apply 1–4 in a follow-up commit if you want.

Open in Web Open in Cursor 

@IMisbahk IMisbahk left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Review

The direction matches ADR-0003: opt-in packs, argv-only recipes, recommend does not install. Uniqueness tests for current builtins, --pack/--risk filtering, and missing-precondition fail-closed look correct.

The blockers are risk labels and contracts on new recipes, not the pack registry shape.

Changes to make before merge

  1. ml.compileall (and ml.mypy) as read-onlycompileall always writes __pycache__. Default balanced policy will mutate the tree with no confirmation.
  2. docs.grep-todogit grep exit 1 on no matches is treated as task failure.
  3. Catalog detail — meaning changed at schemaVersion: 1 (task risk is no longer a bare class; prompt hints are suffixed).
  4. Recommend vs preconditionscompose.yml / terraform/main.tf / docs/ markers do not match the recipes they suggest; confidence: "low" is dead.
  5. New recipes that execute project code (node --test, Playwright, ESLint) should not inherit the old quality.test read-only label if the policy is supposed to mean “no confirmation.”

Residual (pre-existing, not introduced here)

  • execute() uses stdio: "inherit", so live --json runs are not parseable JSON; failed JSON runs return and exit 0.
  • Timeout only sends SIGTERM and can hang if the child ignores it.
  • Unknown taskPolicy in .mstack/config.json fails open; project config can weaken a global strict policy.
  • {{package}} interpolation is not shell injection (shell: false) but can still pass npm flags (--prefix, -g).
  • PackRegistry rejects duplicate task IDs only; specialist/skill/prompt uniqueness is test-enforced on current data, not an invariant at register time. mergeById would silently keep the first collision.

Verification

Read the feature spec, ADR-0003, and the pack/task/catalog/recommend diffs. Specialist passes: code-reviewer and security-reviewer. Did not re-run the suite in this review turn (previous turn: CLI 45 passed, integrations 35 passed / 2 skipped).

I would not merge until 1–4 are fixed. Item 5 can be a follow-up if you explicitly keep npm test as read-only for 0.6 compatibility, but new recipes should not copy that.

),
],
tasks: [
recipe({ id: "ml.compileall", description: "Byte-compile Python sources without executing them.", risk: "read-only", argv: ["python", "-m", "compileall", "-q", "."] }),

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

High: This is labeled read-only, so the default balanced policy runs it with no confirmation, but python -m compileall writes __pycache__ / .pyc and can follow symlinks.

Relabel as working-tree, or drop the recipe. ml.mypy has the same cache-write issue (.mypy_cache).

description: `Reusable engineering template at ${item.path}.`,
})),
...packs.flatMap((pack) => pack.tasks.map((item) => ({ kind: "task-recipes" as const, id: item.id, description: item.description, detail: item.risk }))),
...packs.flatMap((pack) => pack.tasks.map((item) => ({ kind: "task-recipes" as const, id: item.id, description: item.description, detail: `${item.risk} · ${pack.id}` }))),

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Medium: schemaVersion stays 1, but detail changed meaning. 0.6.0 consumers treated task detail as the risk class ("read-only") and prompt detail as argumentHint. They now get "read-only · mobile" and "${hint} · build-like-this".

Keep the old detail meaning and add fields (pack, source), or bump schemaVersion.

),
],
tasks: [
recipe({ id: "infra.tf-fmt-check", description: "Check Terraform formatting without rewriting files.", risk: "read-only", argv: ["terraform", "fmt", "-check", "-recursive"], preconditions: ["main.tf"] }),

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Medium: Recommend markers and recipe preconditions disagree.

  • terraform/main.tf suggests infrastructure-security, but infra.tf-fmt-check requires root main.tf.
  • compose.yml / docker-compose.yml suggest packs, but infra.compose-config requires only compose.yaml. obs.compose-config has no compose-file precondition at all.

Align the marker list with preconditions (any of the compose filenames; main.tf or terraform/main.tf).

tasks: [
recipe({ id: "docs.list", description: "List tracked documentation files.", risk: "read-only", argv: ["git", "ls-files", "--", "docs", "README.md"] }),
recipe({ id: "docs.diff", description: "Show documentation diffs.", risk: "read-only", argv: ["git", "diff", "--", "docs", "README.md"] }),
recipe({ id: "docs.grep-todo", description: "Find TODO markers in documentation.", risk: "read-only", argv: ["git", "grep", "-n", "TODO", "--", "docs"] }),

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Medium: git grep exits 1 when there are no matches, and the runner treats any non-zero as a failed step. A clean docs tree therefore fails this recipe. Empty search is success.

Map exit 1 to success, or do not use git grep's no-match status as failure. Add a docs precondition so a missing pathspec is not a generic 128.

],
tasks: [
recipe({ id: "devtools.pkg-bin", description: "Show package.bin from package.json.", risk: "read-only", argv: ["npm", "pkg", "get", "bin"], preconditions: ["package.json"] }),
recipe({ id: "devtools.node-test", description: "Run Node's built-in test runner.", risk: "read-only", argv: ["node", "--test"] }),

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Medium: qa.node-test / devtools.node-test (and web.eslint / Playwright list recipes) execute project code but are read-only, so they skip confirmation.

This extends the pre-existing quality.test pattern. For new recipes, prefer working-tree whenever the argv loads package.json scripts, test files, or JS/TS config. Keep read-only for commands that cannot execute repository code (git status, terraform fmt -check).

function confidenceFor(reasonCount: number): RecommendationConfidence {
if (reasonCount >= 3) return "high";
if (reasonCount >= 2) return "high";
return "medium";

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Medium: low is on the public type and sort order but never produced. Two reasons and twenty reasons are both high.

Use >= 3 → high, 2 → medium, 1 → low, or drop low from the contract. The recommend test never asserts confidence.

Also: every mstack init repo has docs/, so documentation is always suggested. Cite something more specific than the init template directory.

),
],
tasks: [
recipe({ id: "systems.cargo-check", description: "Typecheck a Rust crate without running tests.", risk: "working-tree", argv: ["cargo", "check", "--locked"], preconditions: ["Cargo.toml"] }),

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Low/medium: --locked requires Cargo.lock. Library crates that only ship Cargo.toml fail this recipe even though the precondition passes.

Drop --locked, or add Cargo.lock as a precondition. Same pattern on systems.cargo-test and graphics.cargo-clippy.

tasks: [
recipe({ id: "devtools.pkg-bin", description: "Show package.bin from package.json.", risk: "read-only", argv: ["npm", "pkg", "get", "bin"], preconditions: ["package.json"] }),
recipe({ id: "devtools.node-test", description: "Run Node's built-in test runner.", risk: "read-only", argv: ["node", "--test"] }),
recipe({ id: "devtools.help", description: "Print this CLI's help.", risk: "read-only", argv: ["node", "--help"] }),

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Low: devtools.help runs node --help, not mstack help. Fix the description or point argv at the mstack binary.

@IMisbahk
IMisbahk marked this pull request as ready for review August 13, 2026 19:28
@IMisbahk
IMisbahk merged commit 65d9bc1 into main Aug 13, 2026
8 checks passed
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