agentsclimarketplace

Propose boundary

Skill KhurrumMahmood/senior-vibe-engineer/.claude/skills/propose-boundary

Turn a confirmed or suspected missing-boundary into a read-only boundary-extraction proposal. Family-local evidence supports Python, TypeScript/checked-JavaScript, Go, Java 17, Kotlin/JVM, C#, Swift 6.3.3, PHP, Ruby, bounded Rust, and bounded Dart. It emits reports/propose-boundary/<target-slug>/proposal.md with candidate seams, public API, compatibility plan, caller impact, and characterization/native-verification plan. Read-only — no edits. Hands off to /refactor-subsystem (decomposition mode).From its SKILL.md

Install
npx -y skills add KhurrumMahmood/senior-vibe-engineer --skill propose-boundary

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

31.9 KB, ~7.3k tokens by cl100k_base, as published. Nobody here has run it

/propose-boundary

Swift 6.3.3 accepted branch

Use scripts/propose_swift.py only for one exact accepted Swift confirmed-omnibus domain, one current complete swift-semantic-facts-v2 pack, and separate hash-bound candidate and proposal verdicts. Keep the copied _swift-semantic-readonly directory beside this selected skill. Pass --omnibus, --facts, --acceptance, --output-dir, --target-name, the configuration and native product/output expectations, and absolute --swift, --swiftc, and --swift-format paths; run --help for the exact CLI.

Consume the final producer selection as authority. Never rerun scope detection or join an older subsystem map. The schema-v2 provider validates the current pack, then runs only as a native verifier on disposable current and exact after trees. For the supported seam, propose exactly three public static export methods behind internal ExportOperations; retain the original DomainOperations public signatures as same-target/module compatibility shims and require their exact resolved callers to remain unchanged.

Emit only proposal.md, evidence.json, and scope.json. Refuse incomplete, stale, tampered, unsafe, or native-failing evidence and Swift/Xcode, mixed-language, protocol/actor, dynamic/reflection, macro/conditional, or ABI-sensitive conditions. Compiler call facts do not prove external callers, runtime behavior beyond the named native checks, ABI/release compatibility, or mutation authority.

C# 14 / .NET 10 accepted branch

Use scripts/propose_csharp.py only for one exact accepted confirmed-omnibus domain, a current complete integrated C# subsystem map and Roslyn fact pack, and a content-addressed csharp-structure-acceptance-v1 candidate/proposal verdict. Keep copied _csharp, _csharp-semantic, and map-subsystem libraries beside the selected skill; run the script with --help for its exact artifact paths and pinned --dotnet argument. Never rerun omnibus detection or mapping inside this consumer.

The branch emits only proposal.md, evidence.json, and scope.json. It preserves the accepted namespace and assembly identities, retains public compatibility shims, records exact resolved caller impact, and proves both the current tree and an independently applied disposable after-tree with native build/test/smoke. Reflection/runtime names, delegates, dispatch, generated or vendor inputs, external callers, conditional variants, framework registration, behavioral equivalence, ABI/release compatibility, and mutation authority stay outside the claim.

Kotlin/JVM 2.4.10 accepted branch

Trigger this branch only for one explicitly scouted Kotlin omnibus domain with a current complete Kotlin map and content-addressed human acceptance. Read ../_kotlin-semantic/GUIDE.md, keep _kotlin-semantic beside the selected skill, and run scripts/propose_kotlin.py with --omnibus, --map-evidence, --acceptance, --output-dir, absolute Kotlin/JVM 2.4.10 --kotlinc, and absolute JDK 17 --java paths; run --help for the exact CLI.

The branch emits only proposal.md, evidence.json, and scope.json, then proves the accepted manifest on the current tree and an exact disposable after-tree. K1 direct facts remain insufficient for overload ambiguity, override/runtime dispatch, reflection/callable references, delegation, generated/KAPT/KSP or plugin inputs, Gradle variants, Java/external callers, behavior, JVM ABI, mutation, or release authority.

C++20 branch

Use scripts/propose_cpp.py with accepted omnibus evidence, a current complete C++20 map, and hash-bound human acceptance; run it with --help for the exact CLI. It emits a read-only plan for one private compiler-owned free-function seam, preserving namespace-qualified signatures, the complete overload set, and direct caller impact. Templates/specializations, dispatch/callbacks, ODR/ABI, external consumers, variants, and mutation are not inferred.

C17 branch

Use scripts/propose_c.py with accepted omnibus scout evidence, a current complete C map, and a hash-bound human acceptance; run the script with --help for the exact CLI. It emits a read-only ready or cohesive-defer outcome. Function pointers, aliases, runtime reachability, alternate variants, external consumers, ABI/layout, linkage, undefined behavior, and mutation remain outside the claim.

PHP and Ruby

For PHP, read _php-proposal/GUIDE.md; for Ruby, read _ruby-semantic/PROPOSAL-GUIDE.md. Consume one accepted upstream selection, preserve its limits, and never rerun boundary detection.

Dart v1

Dart v1 consumes one accepted D4 query pack and human selection. It cites the public seam, callers, barrel compatibility, test surface, and an exact disposable after-tree; cohesive or unresolved targets defer rather than force an extraction.

SKILL_ROOT=".agents/skills/on-demand/propose-boundary"
python3 "${SKILL_ROOT}/scripts/propose_dart.py" \
  --project-root "$PWD" --evidence-dir reports/dart-boundary-evidence \
  --acceptance reports/dart-boundary-evidence/acceptance.json \
  --inspection "$PWD/reports/propose-boundary/dart/inspection.json" \
  --proposal "$PWD/reports/propose-boundary/dart/proposal.md"

Rust v1

Read knowledge/rust-v1.md. The Rust adapter inventories one selected Cargo target, emits distinct JSON/Markdown evidence, and stops at complete/review_boundary; the human still chooses the seam. Macros, build or generated inputs, include contents, cfg variants, traits/generics, unsafe/FFI, and public/semver compatibility stay partial or deferred.

SKILL_ROOT=".agents/skills/on-demand/propose-boundary"
python3 "${SKILL_ROOT}/scripts/propose_rust.py" \
  --project-root "$PWD" --target crates/example \
  --inspection "$PWD/reports/propose-boundary/rust/inspection.json" \
  --proposal "$PWD/reports/propose-boundary/rust/proposal.md"

The canonical producer is .claude/skills/_common/scripts/rust_proposal_evidence.py; a copied projection places the same bytes beside the adapter under the alias rust_project_evidence.py.

You are the orchestrator for turning a suspected missing-boundary target into a read-only boundary-extraction proposal. The user has named a file or directory where distinct concerns live together without an explicit contract; your job is to score the candidate seams, propose the public API surface, sketch the backward-compat shim, and emit a proposal the human reviews before handing off to /refactor-subsystem.

You do NOT move files, rename modules, edit any source, or touch imports in this skill. The only artifact you produce is reports/propose-boundary/<target-slug>/proposal.md plus its supporting inspection.json.

How success is judged

  • proposal.md is complete per the template: candidate seams with raw scores, proposed public API table, backward-compat shim shape, caller-impact summary, and characterization-test matrix.
  • When inspection.json carries defer_signals, the proposal front matter records recommendation: defer_<reason> — never a forced refactor recommendation.
  • Zero production edits — the run writes only under reports/propose-boundary/<target-slug>/; the hand-off to /refactor-subsystem is named, not executed.

Core beliefs

  1. This is boundary proposal, not boundary decision. The skill surfaces candidate seams + their evidence; the human picks. Over- surface and let the human prune — same posture as /find-orphaned-ideas --todo.
  2. Heuristics are evidence, not verdict. Co-edit frequency, mutual import directionality, naming alignment, and cross-cluster call-edge density are signals. Each candidate seam carries the raw scores so the human can judge whether the cluster is coherent or coincidental.
  3. Backward-compat shim is the migration's safety net. Every proposal sketches a re-export __init__.py that keeps existing call sites working after the move. If a caller reaches into a private helper across the proposed boundary, the shim won't cover it — that caller becomes a Phase 1 blocker, not a Phase 2 cleanup.
  4. Characterization tests pin behavior before the move. Every public-API symbol gets 2–4 pin tests (input → expected output / side-effect) that must pass before AND after the refactor. Same discipline as a behavior-preserving two-commit refactor.
  5. The skill ecosystem is a valid target. Large composite skills (a seven-phase orchestrator, a cross-cutting aggregator) are themselves boundary-design candidates. When the target is a skill directory, sub-phases (parsed from SKILL.md ## Phase N headings) are treated as symbols, the phase number as the cluster signal, and the proposal includes an "Orchestration shim shape" section sketching how the original skill name keeps working after split.

TypeScript / TSX and checked-JavaScript v1

The inherited TypeScript subset was scans: [python, typescript]; the frontmatter declaration adds JavaScript only for the checked-JavaScript path described here.

Use this branch only when the target host supplies one named, project-local tsconfig.json and its own installed typescript package. The bundled runner uses that host's Compiler API to resolve eligible static module specifiers, top-level target symbols, and target-local call targets. The final artifact is an inspection.json plus proposal.md, not a lexical suggestion: it cites the resolved direct, alias, and barrel import evidence it used.

This is the minimum framework-neutral typed-source contract. Checked JavaScript uses --language javascript, a named jsconfig.json or tsconfig.json, and compilerOptions.allowJs plus checkJs set to true. It accepts .js, .jsx, .mjs, and .cjs (including a mixed JS/TS host) and records selected files outside that named config as partial, never a clean proposal:

  • Propose a boundary only when two or more coherent top-level symbol domains form a partition within the target. Public API candidates are exported, non-underscore symbols; underscore-prefixed reaches are explicit Phase 1 blockers rather than compatibility coverage.
  • Record resolved inbound and outbound static imports, target-local resolved calls, direct/alias/barrel caller impact, and a compatibility plan that keeps the existing TypeScript index.ts/index.tsx or JavaScript index.js/index.jsx/index.mjs/index.cjs barrel as a temporary re-export surface.
  • In checked JavaScript, treat only same-name, top-level declaration references assigned through literal exports.name, module.exports.name, or module.exports = { name } forms as resolved CommonJS public API evidence. Computed, spread, aliased, or expression-backed CommonJS exports make the proposal partial until source/runtime confirmation establishes the public contract.
  • Give a characterization matrix and cite the host's native typecheck/test commands for the human-approved move. The proposal never edits source or runs a codemod.
  • Defer explicitly when the target has unresolved or ambiguous module/symbol facts. A cohesive one-domain target also defers rather than inventing a split. Excluded generated/vendor/test/declaration/minified/build trees stay excluded even when named directly.

This v1 does not infer framework semantics: React, Node, ORM, route, dependency-injection, runtime loading, dynamic import, reflection, decorator, or other framework behavior. It does not follow directory symlinks and rejects a direct symlink target. A missing or invalid tsconfig, missing project-local TypeScript, or syntax error stops clearly with exit code 2. Type errors outside the selected proposal graph are not converted into framework facts.

The resolver lives in this skill because its output contract is specific to boundary proposals. Do not extract it into a shared TypeScript platform until another accepted consumer proves the same resolution and deferral contract.

Installed TypeScript proposal command

Run this from the target host root after installing only this selected skill. It writes only under reports/propose-boundary/ and has no repository-level Python, _common, or sibling-skill import.

To make the stock Codex location from a released source, set PROPOSE_BOUNDARY_SOURCE to that pinned source/ref and run:

<!-- installed-command:stock-install:start -->
: "${PROPOSE_BOUNDARY_SOURCE:?Set this to the pinned skill source/ref}"
npx --yes [email protected] add "${PROPOSE_BOUNDARY_SOURCE}" \
  --skill propose-boundary --agent codex --copy -y
<!-- installed-command:stock-install:end --> <!-- installed-command:typescript-proposal:start -->
PROPOSE_TARGET="${PROPOSE_TARGET:-src/legacy}"
PROPOSE_LANGUAGE="${PROPOSE_LANGUAGE:-typescript}" # typescript | javascript
PROPOSE_TSCONFIG="${PROPOSE_TSCONFIG:-tsconfig.json}"
PROPOSE_NAME="${PROPOSE_NAME:-${PROPOSE_LANGUAGE}-legacy}"
SKILL_ROOT=""
for SKILL_CANDIDATE in \
  ".agents/skills/propose-boundary" \
  ".claude/skills/propose-boundary"
do
  if [ -f "${SKILL_CANDIDATE}/SKILL.md" ]; then
    SKILL_ROOT="$(cd "${SKILL_CANDIDATE}" && pwd)"
    break
  fi
done
if [ -z "${SKILL_ROOT}" ]; then
  printf '%s\n' "propose-boundary is not installed in .agents/skills or .claude/skills" >&2
  exit 2
fi
node "${SKILL_ROOT}/scripts/propose_typescript.mjs" \
  --target "${PROPOSE_TARGET}" \
  --project-root "$(pwd)" \
  --language "${PROPOSE_LANGUAGE}" \
  --tsconfig "${PROPOSE_TSCONFIG}" \
  --candidates 2 \
  --inspection "reports/propose-boundary/${PROPOSE_NAME}/inspection.json" \
  --proposal "reports/propose-boundary/${PROPOSE_NAME}/proposal.md"
<!-- installed-command:typescript-proposal:end -->

Go v1

The former scans: [python, typescript, javascript] declaration is superseded by the frontmatter Go entry; existing Python and TypeScript/checked-JavaScript contracts are unchanged.

Use this branch for one package directory in one Go module. It is a deliberately narrow, read-only proposal: host go list -e -json -mod=readonly ./... establishes the module's active package/import facts, while the bundled standard-library Go program uses go/parser/go/ast for top-level declarations and syntax-level local-call candidates. It never downloads or imports go/packages, go/types, a language server, or any third-party module.

Go v1 may recommend an extraction only when all of these facts are available:

  • a PATH-discovered Go tool is at least Go 1.22 and the target host is one root go.mod module with no active go.work workspace and no replace directive (preflighted with go env GOWORK and go mod edit -json);
  • go list establishes the target package import path and every first-party direct or alias importer;
  • the target has two or more named top-level symbol domains, each with at least two declarations; and
  • no build-tag/cgo source, unresolved package graph, dot/blank importer, or generated/vendor/test target makes the evidence incomplete.

Uppercase identifiers are the only public API candidates. Go cannot import an unexported identifier from another package, so package-private cross-domain calls are listed as migration blockers rather than a TypeScript-style external private-import claim. Those calls are AST syntax candidates, not go/types call identities. For each selected exported function, the proposal also lists same-package exported named types found in its syntax-level signature so the human can explicitly preserve their identity with a temporary type alias. The proposal preserves the old package import path only as a human-approved temporary forwarding/type-alias facade; it never writes one.

This v1 explicitly defers active go.work workspaces, modules using replace, build-tagged or cgo target source, dot/blank importers, unresolved packages, generated/vendor/test targets, and cohesive one-domain packages. The bundled runner avoids Go 1.18-only syntax so an older toolchain reaches the explicit Go-version deferral rather than failing to compile the runner. Dynamic loading, reflection, interfaces, build matrices, workspaces, external consumers, and runtime reachability remain outside the claim. A missing or old Go tool emits an unsupported inspection outcome rather than a clean proposal. Malformed Go source emits a failed syntax outcome.

Installed Go proposal command

Run this from the Go module root after the router has exposed the on-demand library. It uses only the selected skill's bundled Go source and the host Go toolchain; it does not require the toolkit Python environment, sibling skills, or a network dependency.

<!-- installed-command:go-proposal:start -->
PROPOSE_TARGET="${PROPOSE_TARGET:-internal/legacy}"
PROPOSE_NAME="${PROPOSE_NAME:-go-legacy}"
SKILL_ROOT=""
for SKILL_CANDIDATE in \
  ".agents/skills/propose-boundary" \
  ".claude/skills/propose-boundary"
do
  if [ -f "${SKILL_CANDIDATE}/SKILL.md" ]; then
    SKILL_ROOT="$(cd "${SKILL_CANDIDATE}" && pwd)"
    break
  fi
done
if [ -z "${SKILL_ROOT}" ]; then
  printf '%s\n' "propose-boundary is not installed in .agents/skills or .claude/skills" >&2
  exit 2
fi
if ! command -v go >/dev/null 2>&1; then
  printf '%s\n' '{"status":"unsupported","failure_kind":"go_tool_missing"}'
  exit 0
fi
GO_VERSION_OUTPUT="$(go version 2>/dev/null || true)"
GO_VERSION_TOKEN="${GO_VERSION_OUTPUT#* go}"
GO_VERSION_TOKEN="${GO_VERSION_TOKEN%% *}"
GO_VERSION_MAJOR="${GO_VERSION_TOKEN%%.*}"
GO_VERSION_REST="${GO_VERSION_TOKEN#*.}"
GO_VERSION_MINOR="${GO_VERSION_REST%%.*}"
case "${GO_VERSION_MAJOR}:${GO_VERSION_MINOR}" in
  *[!0-9:]*|:*)
    printf '%s\n' '{"status":"unsupported","failure_kind":"go_version_unreadable","minimum_go":"1.22"}'
    exit 0
    ;;
esac
if [ -z "${GO_VERSION_MAJOR}" ] || [ -z "${GO_VERSION_MINOR}" ] || \
   [ "${GO_VERSION_MAJOR}" -lt 1 ] || \
   { [ "${GO_VERSION_MAJOR}" -eq 1 ] && [ "${GO_VERSION_MINOR}" -lt 22 ]; }
then
  printf '%s\n' '{"status":"unsupported","failure_kind":"go_version_too_old","minimum_go":"1.22"}'
  exit 0
fi
go run "${SKILL_ROOT}/scripts/propose_go.go" \
  --target "${PROPOSE_TARGET}" \
  --project-root "$(pwd)" \
  --candidates 2 \
  --inspection "reports/propose-boundary/${PROPOSE_NAME}/inspection.json" \
  --proposal "reports/propose-boundary/${PROPOSE_NAME}/proposal.md"
<!-- installed-command:go-proposal:end -->

Java v1

Use this branch for one named Java package directory in a standalone host that can compile with JDK 17 without Maven, Gradle, annotation processors, or third-party dependencies. The bundled single-file Java runner invokes the JDK compiler tree API with parsing and attribution enabled. Only after all eligible production sources attribute successfully does it report direct imports or fully-qualified type references as compiler-resolved caller evidence.

Java v1 proposes a seam only when at least two leading type-name domains each contain at least two top-level types. Public top-level types are proposed as the compatibility surface; the human still chooses the boundary. A one-domain package defers instead of inventing a split. Generated, vendor, build, test, malformed, default-package, mixed-package, and symlink targets never produce a clean proposal.

This is deliberately a source/package pilot. It does not infer Spring, Jakarta, Android, reflection, dependency injection, runtime class loading, module-path, annotation-processor, Kotlin, Maven, or Gradle semantics. Hosts requiring those facts defer until a framework- or build-aware contract is justified by a real project. The runner stays family-local and uses no repository Python runtime, language server, or third-party JAR.

Installed Java proposal command

Run this from the host root after the router exposes the on-demand skill. Both java and javac must resolve from PATH; source-file mode executes the copied runner directly.

<!-- installed-command:java-proposal:start -->
PROPOSE_TARGET="${PROPOSE_TARGET:-src/main/java/example/legacy}"
PROPOSE_NAME="${PROPOSE_NAME:-java-legacy}"
SKILL_ROOT=""
for SKILL_CANDIDATE in \
  ".agents/skills/propose-boundary" \
  ".claude/skills/propose-boundary"
do
  if [ -f "${SKILL_CANDIDATE}/SKILL.md" ]; then
    SKILL_ROOT="$(cd "${SKILL_CANDIDATE}" && pwd)"
    break
  fi
done
if [ -z "${SKILL_ROOT}" ]; then
  printf '%s\n' "propose-boundary is not installed in .agents/skills or .claude/skills" >&2
  exit 2
fi
if ! command -v java >/dev/null 2>&1 || ! command -v javac >/dev/null 2>&1; then
  printf '%s\n' '{"status":"unsupported","failure_kind":"jdk_tool_missing","minimum_jdk":17}'
  exit 0
fi
java "${SKILL_ROOT}/scripts/propose_java.java" \
  --target "${PROPOSE_TARGET}" \
  --project-root "$(pwd)" \
  --minimum-jdk 17 \
  --candidates 2 \
  --inspection "reports/propose-boundary/${PROPOSE_NAME}/inspection.json" \
  --proposal "reports/propose-boundary/${PROPOSE_NAME}/proposal.md"
<!-- installed-command:java-proposal:end -->

Python scope

  • Project root: the working directory.
  • Python: the host project's venv python (.venv/bin/python or equivalent) for the helper script — it routes Python parsing through the shared per-language adapter registry (ADR 0032; Python-only here, skipping files whose adapter can't supply the raw AST) and shells out to git log for co-edit frequency; stdlib + git only.
  • Output: reports/propose-boundary/<target-slug>/. Never touches any other file.
  • Read-only. No file moves, no edits, no Edit tool. The orchestrator's allowed-tools list intentionally excludes Edit.

Argument parsing

Two forms.

Form A — file or directory target

/propose-boundary <path>

e.g. /propose-boundary <project>/tasks/shared_helpers.py or /propose-boundary <project>/services/sites/. The target may be a single Python file, a directory containing Python files, or a skill directory (.claude/skills/<name>/). The helper auto-detects which.

Form B — subsystem name

/propose-boundary <subsystem-name>

If .engineering/docs/subsystems/<subsystem-name>.md exists, the helper reads it for the file list and uses that as the target. Otherwise the orchestrator treats the argument as a path and falls through to Form A.

Optional flag — --candidates N

/propose-boundary <target> --candidates 3

Requests N alternative boundary cuts (default: 1). The helper scores every candidate seam against the full criterion set and returns the top N plus every candidate tied at the cutoff. candidate_selection records the requested, eligible, and returned counts, cutoff score, whether ties expanded the result, and every lower-scored omitted candidate. Returned tie identities and scores remain in candidate_seams, so a limit never silently hides a cutoff-equivalent seam. The human picks one (or none) before hand-off.

If the target doesn't exist, has fewer than 2 Python files AND fewer than 6 public symbols total, the orchestrator stops, logs target_not_found or target_below_threshold to the proposal, and returns.

Pipeline

Stage 0 — resolve target. Parse the argument. Detect target kind: file | directory | skill_directory. Compute the target slug (replace / with -, drop leading dots and .py).

Stage 1 — inspect. Run the helper:

.venv/bin/python .claude/skills/propose-boundary/scripts/propose.py \
  --target <path> \
  --project-root . \
  --candidates <N> \
  --output reports/propose-boundary/<target-slug>/inspection.json

The helper writes inspection.json with:

  • target — resolved path + target kind.
  • files — every Python file in scope with line count and public symbols list.
  • symbols{name, file, kind, public} for every top-level symbol (functions, classes, module-level constants). For skill-directory targets, also includes virtual phaseN_* / phaseN_M_* symbols parsed from SKILL.md ## Phase N / ### N.M headings.
  • co_edit_pairs — top symbol pairs by co-edit frequency, from a git log --name-only walk over the last 90 days (configurable).
  • naming_clusters — lexical-prefix clusters; each cluster names members and a proposed cluster name.
  • call_edges{caller, callee, count} for every cross-symbol call resolved within the target.
  • candidate_seams — list of {cluster_id, members, rationale, proposed_public_api, callers_into_private_helpers, scores} for the top N candidate boundary cuts plus every seam tied at the cutoff.
  • candidate_selection{requested, eligible, returned, cutoff_score, ties_included, omitted_count, omitted}. Each omitted row names its cluster_id and score.
  • defer_signals — guardrail trips (target_below_threshold, single_cluster_no_seam, scratch_code).

Stage 2 — scout callers (optional). For each proposed_public_api symbol in every returned candidate seam, the orchestrator dispatches a cheap read-only scout via .claude/skills/_common/dispatch_scout_cheap.sh (Bash + grep — no Agent tool; the allowed-tools list stays read-only-tight) to confirm the call sites in callers_into_private_helpers. The orchestrator may skip this if the helper's static analysis already covered the project root. This cheap-dispatch path requires the host tools.code_agent backend (<!-- host-adapter -->); use inline scouting when that backend is absent.

Stage 3 — synthesize. The orchestrator reads inspection.json and writes proposal.md per the template below. This is judgment work, not mechanical — Claude does it, not a script.

Stage 4 — stop or hand off. If defer_signals are non-empty, the proposal records recommendation: defer_<reason> in the front matter. Otherwise the proposal recommends recommendation: refactor and names /refactor-subsystem --target <target-slug> as the next step.

Proposal template

The proposal markdown has these sections, in order:

# Boundary proposal — <target>

> **Detected by:** `/propose-boundary` (read-only; no edits applied)
> **Decided in:** <host project's ADR on staged boundary
> rearchitecting, if one exists — see the host decision registry>
> **Executed by:** `/refactor-subsystem` (decomposition mode)

**Recommendation:** refactor | defer_<reason>
**Target kind:** file | directory | skill_directory
**Total LOC:** <N>
**Public symbols:** <K>
**Candidate seams:** requested <N>; returned <R> of <C> eligible;
cutoff <S>; ties included: yes | no; omitted <O>

## Current shape

(File tree + documented or detected domains.)

## Candidate seam 1 — <cluster_id> (score: <S>)

**Members.** <symbol list>.

**Rationale.** <why this cluster is coherent — naming alignment,
co-edit frequency above threshold, low cross-cluster call density,
docstring evidence>.

**Proposed public API.**

| Symbol | Signature | Purpose |
|---|---|---|

**Backward-compat shim shape.**

(Python `__init__.py` re-export block keeping existing call sites
working after extraction.)

**Caller-impact summary.**

| Importer | Statement | Shim covers? |
|---|---|---|

**Characterization-test matrix.**

| Public-API symbol | Pin test 1 | Pin test 2 |
|---|---|---|

## Candidate seam 2 — <cluster_id> (score: <S>)

(Repeat this section for every row in `candidate_seams`, including ties that
expanded the result beyond requested N.)

## Orchestration shim shape (skill-directory targets only)

(How the original skill name keeps working after split — thin
orchestrator that invokes new sub-skills in sequence.)

## Migration sequencing (per candidate seam)

1. Pre-move pin-tests.
2. Phase 1: migrate reach-into-private callers.
3. Phase 2: extract cluster (`/refactor-subsystem` decomposition mode).
4. Phase 3: clean up dead re-exports.

## Stop condition

(Behavior preservation + test suite green + every importer routed
through new boundary.)

## Spec hand-off (for /refactor-subsystem)

\`\`\`yaml
---
spec_id: boundary-<target-slug>-<cluster_id>
status: STUB
target: refactor-subsystem
code_roots:
  - <target>
strategy: decomposition
boundary_proposal: reports/propose-boundary/<target-slug>/proposal.md
---
\`\`\`

## Notes (orchestrator judgment)

A short prose section.

Defer signals

  • target_below_threshold — fewer than 2 Python files AND fewer than 6 public symbols. Proposal recommends defer_below_threshold.
  • single_cluster_no_seam — every candidate seam scores below the threshold; the target's symbols are tightly co-coupled (high cross- cluster call density everywhere). Proposal recommends defer_no_seam and points the human at the SUSPECT step (/find-omnibus for an intra-file split).
  • scratch_code — the target matches a known scratch-code path (host-project-configured prefix list). Proposal recommends defer_scratch_code.

Calibration

  • Co-edit window defaults to 90 days. Override with --co-edit-days N.
  • Naming-cluster minimum defaults to 3 members. Override with --min-cluster-size N.
  • Seam-score threshold defaults to 0.4. Override with --seam-threshold T.
  • The skill is intentionally over-permissive on emit; the human prunes. Same posture as /find-orphaned-ideas --todo.

Re-runs are idempotent

The helper reads the filesystem and git log only. Re-running with the same target overwrites inspection.json and is safe. The proposal is NOT auto-overwritten — Claude inspects the existing proposal first and only rewrites the sections that changed.

Repository layout

.claude/skills/propose-boundary/
├── SKILL.md          # this file — orchestrator
└── scripts/
    └── propose.py    # detector + scoring helper (stdlib + git only)

Next skills

  • /refactor-subsystem in decomposition mode — executes the proposal under a behavior-preserving two-commit discipline. One candidate seam per PR.
  • /decide if the proposal surfaces a tradeoff the host project's decision registry doesn't yet cover.
  • /map-subsystem to refresh the subsystem map after the extraction lands.

Related

  • architectural-smells.md smell 9 (missing-boundary) — detector entry that names this skill as the SUSPECT.
  • /map-subsystem — Stage 4 dep-graph output hints at low-density inter-cluster edges that may indicate a missing boundary.
  • Host-project ADR on staged boundary rearchitecting (when authored) — names the when-to-phase decision framework this skill pairs with.

What ships with it: 14 files

260.0 KB alongside SKILL.md, 11 of them executable

knowledge/

scripts/

Keep looking

Skills are one crate of 326,750. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.