Skip to content

feat: first-class monorepo support (detection, per-workspace attribution, dependency graph)#9

Merged
maxgfr merged 7 commits into
mainfrom
feat/monorepo-support
Jun 10, 2026
Merged

feat: first-class monorepo support (detection, per-workspace attribution, dependency graph)#9
maxgfr merged 7 commits into
mainfrom
feat/monorepo-support

Conversation

@maxgfr

@maxgfr maxgfr commented Jun 10, 2026

Copy link
Copy Markdown
Owner

Context

Workspaces were only detected (npm/yarn/pnpm) and surfaced as metadata — the whole pipeline ran globally on the repo, so a monorepo's inventory was misleading: one merged StackInfo, routes from several apps mixed together, a flat feature list, and dependencies read only from the root manifest. The playbook just told the agent to re-scope manually.

This PR makes monorepo support first-class: broader detection, per-workspace attribution, an inter-workspace dependency graph, features grouped by workspace, while keeping a single output tree. Single-package repos are byte-identical to before.

What's in it (7 commits, one per step)

  1. Detection élargie (src/detect/workspaces.ts, new module) — npm/yarn/pnpm (incl. pnpm ! negation patterns), lerna.json/nx.json fallbacks, Cargo [workspace] members/exclude, go.work use directives; polyglot union. Each workspace carries a kind.
  2. Dependency graphdependsOn from manifests (npm names, Cargo path/name deps, go.mod require/replace) + topoOrderWorkspaces (Kahn, deterministic fallback on cycles).
  3. Per-workspace attribution — each inventory.workspaces[*] carries its own stack, dependencies, fileCount/routeCount, schemas, and filtered hints; routes are tagged with their workspace. Workspace stacks are detected before routes and merged into the global stack — otherwise a monorepo whose root manifest doesn't declare the app framework (the normal case) never activated the route adapters.
  4. Features grouped by workspace — app workspaces split into web-dashboard-style sub-features; library workspaces collapse into one feature each; rank-offset by topological position so shared packages build before the apps that consume them.
  5. Rendering## Workspaces table in ARCHITECTURE.md, a second mermaid graph in diagram.md, the topo-order blurb in REBUILD.md, workspaces + edges in SUMMARY.md and the CLI log. All absent for single-package repos.
  6. Fixtures — real Next.js routes in the npm monorepo fixture, plus new cargo-workspace and go-work fixtures, tested end to end.
  7. AI playbook & docs — SKILL.md step 3, the playbook's §Monorepo, a new references/stack-guides/monorepo.md (incl. the on-the-fly fallback: the agent identifies workspaces itself and scopes re-runs with --include when detection misses an unconventional layout), README + DOCUMENTATION.

Known limitation (out of scope, noted in the guide)

The Next.js adapter only recognizes apps/*/packages/* prefixes — a workspace at services/web won't get its routes resolved deterministically. A follow-up could thread detected workspace paths into detectRoutes.

Verification

  • pnpm run typecheck
  • pnpm test326 passed (was 296) ✓
  • pnpm run check:build — bundle regenerated & committed ✓
  • pnpm run parity — PASS ✓
  • pnpm run demo — sample-app output unchanged (single-package invariance) ✓

🤖 Generated with Claude Code

maxgfr and others added 7 commits June 10, 2026 15:36
detectWorkspaces moves to src/detect/workspaces.ts (re-exported from
stack.ts for compatibility) and gains: a kind tag per workspace (npm,
pnpm, lerna, nx, cargo, go), pnpm negation patterns, lerna.json /
nx.json membership fallbacks when package.json declares none, Cargo
[workspace] members/exclude, and go.work use directives. Polyglot
monorepos union all ecosystems.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
buildWorkspaceGraph fills each workspace's dependsOn from manifest
declarations — package.json deps matching sibling names, Cargo name or
path dependencies, go.mod require/replace of sibling modules — and
topoOrderWorkspaces returns a deps-first order (Kahn, deterministic
path-order fallback on cycles).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Each detected workspace now carries its own stack (detected from its
rebased files and manifests), its own dependency manifests, its file
and route counts, its schema files, and the global hints filtered to
its subtree; routes are tagged in place with their workspace.

Workspace stacks are detected before route detection and their
frameworks merged into the global stack — previously a monorepo whose
root manifest didn't declare the app framework (the normal case) never
activated the route adapters, so workspace apps had no routes at all.
The monorepo fixture gains real Next.js routes to lock this in.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
buildFeatures gains an optional workspaces parameter: in a monorepo an
app workspace (it owns routes) splits into per-area sub-features named
'Web · Dashboard' (slug web-dashboard), a library workspace collapses
into a single feature ('UI (@acme/ui)'), and every workspace group is
rank-offset by its topological position so shared packages always
build before the apps that consume them. Trivial app groups fold into
that app's own core; the no-workspaces path is byte-identical to the
previous behavior.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ARCHITECTURE.md gains a ## Workspaces table (workspace, path, kind,
stack, depends-on, routes) with an agent note to verify roles and
extend the graph with implicit edges; diagram.md gains a second
mermaid graph of the manifest-declared workspace edges; REBUILD.md
states that the outer build tier is the workspace topological order;
SUMMARY.md lists each workspace with its edges. All sections are
absent for single-package repos.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Two new fixtures lock the non-JS workspace paths end to end: a Rust
cargo workspace (glob members, exclude, a path dependency edge) and a
go.work monorepo (block-form use, module naming from go.mod, a
require/replace edge), each asserting per-workspace stack attribution
and shared-package-first build order.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
SKILL.md step 3 now describes the per-workspace inventory fields and
the on-the-fly fallback (the agent identifies workspaces itself and
scopes re-runs with --include when detection misses an unconventional
layout); the playbook's §Monorepo shifts the agent's job to verifying
roles and extending the graph with implicit edges; a new
references/stack-guides/monorepo.md covers the supported systems,
per-workspace analysis, shared-package PRD pattern, and pitfalls;
README and DOCUMENTATION document the enriched workspaces schema.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@maxgfr maxgfr merged commit 31f49c1 into main Jun 10, 2026
2 checks passed
@maxgfr maxgfr deleted the feat/monorepo-support branch June 10, 2026 13:58
github-actions Bot pushed a commit that referenced this pull request Jun 10, 2026
# [0.11.0](v0.10.2...v0.11.0) (2026-06-10)

### Features

* first-class monorepo support (detection, per-workspace attribution, dependency graph) ([#9](#9)) ([31f49c1](31f49c1))
@github-actions

Copy link
Copy Markdown

🎉 This PR is included in version 0.11.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant