tech-stack-capture
Skill0 starsChanged 3 months agoMITView on GitHub
Captures or refreshes the `tech_stack:` block in a Portfolio-Member's `project/portfolio.yml` per the canonical-language file under `spec/portfolio/tech-stack-discovery/` §Discovery sequence. Probes repo signals (lockfiles, `Taskfile.yml`, `.github/workflows/`, `renovate.json5`, `mkdocs.yml`, `.vale.ini`, `.pre-commit-config.yaml`), classifies hits against the closed `kind` (12) and `group` (5) enums from `spec/portfolio/tech-stack/`, compares each candidate against the global stack, drops inherited matches, and confirms every proposed change interactively before writing. Invoke when the user asks to "capture the tech stack", "scaffold a tech_stack block", "refresh the tech_stack section", or equivalent German-language requests. Don't use to author `portfolio/tech-stack.yml` (hand-curated only) or to run signal-verification audits (use `portfolio-audit`). Supports resume on re-invocation per `spec/claude/resumable-work/`.
In this repository36 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- audience-identifySkill
- backlog-delivery-orchestrateSkill
- backstage-catalog-generateSkill
- blog-authorSkill
- blog-author-triggerSkill
- cicd-pipeline-designSkill
- continuous-improvement-triageSkill
- cookiecutter-template-manageSkill
- docs-audience-tracks-applySkill
- docs-dry-refactorSkill
- github-issue-templates-applySkill
- issue-backlog-partitionSkill
- issue-batch-orchestrateSkill
- issue-orchestrateSkill
- lektorat-applySkill
- lektorat-auto-reviseSkill
- mermaid-diagrams-applySkill
- mkdocs-structure-applySkill
- permission-allowlist-maintainSkill
- portfolio-auditSkill
- portfolio-inflight-triageSkill
- project-structure-applySkill
- pull-request-createSkill
- pull-request-mergeSkill
- pull-request-runner-sweepSkill
- readme-structure-applySkill
- release-notes-curateSkill
- release-publish-triggerSkill
- requirements-elicitSkill
- spec-drift-auditSkill
- specSkill
- vocab-drift-auditSkill
- workflow-health-triageSkill
- working-copy-startSkill
- yaml-json-schemaSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
17 rules. About 0 are common, 3 are distinctive, and 14 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈3
Distinctive · estimate
This author's own choices. Worth a look.
14
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 50
If the active repository carries no project/portfolio.yml at all, stop and route the operator to portfolio-audit Bootstrap.
- Very specific: line 52
If the active repository ships its own portfolio/tech-stack.yml and isn't claude-shared, stop with a Critical warning: a Portfolio-Member …
- Distinctive: line 56
Before any signal probe, confirm:
- Very specific: line 72
When project/portfolio.yml already carries a non-empty tech_stack: block, parse it into three working sets:
- Very specific: line 82
Read the signal-source set in the order documented in references/signal-source-map.md, and read that file now to ground every …
- Distinctive: line 112
Don't proceed to step 8 until every proposed addition, override, and regroup has been individually confirmed, edited, or rejected.
- Very specific: line 135
Read examples/01-fresh-capture-empty-additions.md when running a fresh capture on a project with no existing tech_stack: additions.
- Very specific: line 136
Read examples/02-refresh-after-dep-bot-swap.md when refreshing the tech-stack capture after Dependabot or Renovate has swapped a dependency.
- Very specific: line 137
Read examples/03-deviation-with-override-and-regroup.md when the project deviates from the portfolio baseline and you need to see how …
- Very specific: line 145
Never write project/portfolio.yml without an interactive per-entry confirmation round (steps 7) on every addition, override, and regroup.
- Very specific: line 146
Never modify the global manifest portfolio/tech-stack.yml from this skill, in any repository.
- Very specific: line 147
Never declare an additions[] entry that matches an inherited entry on both name and kind.
- Very specific: line 148
Never write an overrides[] record with an empty or whitespace-only rationale.
- Very specific: line 149
Never write a regroup[] record whose new group equals the inherited entry's group (no-op regroup) or whose rationale is empty.
- Distinctive: line 150
Never invent a signal hit.
- Very specific: line 152
Never commit a "candidates not picked" log to the repository.
- Very specific: line 153
When spec/portfolio/tech-stack-discovery/ or spec/portfolio/tech-stack/ disagrees with this skill, the spec wins.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Tech Stack Capture
Drives the §Discovery sequence per repository defined in spec/portfolio/tech-stack-discovery/<canonical_language>.md and produces a tech_stack: block in project/portfolio.yml that conforms to the entry schema, the inheritance contract, the kind enum (12 values), the group enum (5 values), and the regroup mechanism declared in spec/portfolio/tech-stack/<canonical_language>.md. One operation — fresh capture and refresh share the same path because the spec doesn't distinguish them.
German trigger phrases
This skill also triggers on equivalent German-language requests, including:
- "Tech-Stack erfassen"
- "tech_stack-Block aktualisieren"
Why this is a skill, not an agent
- Per-entry interactive confirmation is a MUST. The discovery spec requires the maintainer to accept, reject, or edit every proposed entry, override, and regroup before any write. An agent's fire-and-forget contract would lose that checkpoint per candidate.
- Persistent on-disk artefact under iterative drafting. The skill mutates
project/portfolio.yml(a top-level repo artefact alongsideproject/mission.mdandproject/roadmap.md); the iterative drafting (signal probe → propose → confirm → write) flows back into the main conversation naturally. - Cross-spec orchestration. The skill reads the global manifest, the schema spec, and the discovery spec, then writes per the project's primary YAML conventions. Multi-source orchestration belongs in the skill layer per
spec/claude/skill-vs-agent/. - Counter-dimension considered: a tool-restricted signal-probing agent could absorb the file-system reads more cleanly, but the load-bearing work is the per-entry conversation with the maintainer, not the probing — skill wins.
User-language policy
Detect the user's language and respond in it. YAML content written to project/portfolio.yml stays English (the file's existing convention; identifiers, kind/group enum tokens, and the rationale: prose all stay English regardless of the user's conversation language, matching how every other portfolio manifest in the nolte/* portfolio is authored).
Detection: am I in the right repository?
The skill runs in two roles depending on the active repository:
- Inside any Portfolio-Member repository (the typical adopter — repo under
nolte/*with aproject/portfolio.yml): the operation runs end-to-end against that repo'sproject/portfolio.yml. Detection: presence ofproject/portfolio.ymlAND absence of.claude-plugin/plugin.json(so this isn'tclaude-shareditself unless explicitly so). - Inside
claude-shared(where the global stack lives plus this repository's ownproject/portfolio.yml): the operation runs againstclaude-shared's ownproject/portfolio.yml. Detection: presence of.claude-plugin/plugin.jsonANDportfolio/tech-stack.ymlANDproject/portfolio.yml.
If the active repository carries no project/portfolio.yml at all, stop and route the operator to portfolio-audit Bootstrap; the per-repo tech_stack: block requires the manifest to exist first per spec/portfolio/portfolio-management/ §Capability inventory per repository.
If the active repository ships its own portfolio/tech-stack.yml and isn't claude-shared, stop with a Critical warning: a Portfolio-Member shipping its own global manifest is forbidden per spec/portfolio/tech-stack/ §Global tech-stack manifest.
Preconditions
Before any signal probe, confirm:
project/portfolio.ymlexists and parses as YAML. Missing or malformed manifests block the skill; route the operator toportfolio-auditBootstrap or to fixing the parse error first.- The global manifest at
claude-shared:portfolio/tech-stack.ymlis reachable. When the active repository isclaude-shared, read it locally. From any other repo, fetch viagh api repos/nolte/claude-shared/contents/portfolio/tech-stack.yml --jq .content | base64 -dand discard the raw content once a structured per-entry summary (name, kind, group, status) is in hand. Network-unreachable global manifests block the skill with an explicit error; don't proceed against a stale local cache without operator acknowledgement. - The active repository is on a feature branch (per
spec/project/branching-model/), notdevelopormain. Confirm viagit rev-parse --abbrev-ref HEAD. Capturing on a protected branch is a structural error and is refused even if file writes would technically succeed.
Operations
The single operation produces a tech_stack: block in project/portfolio.yml (creating it on a fresh capture, replacing it on a refresh). Run the eight steps in order; reordering breaks the spec's discovery sequence.
1. Resolve the inherited set
Parse the fetched global manifest into the inherited set: every entry whose status is active or experimental. Drop deprecated entries from the inherited working set but keep them visible for later step 7 (deprecation-deviation prompt). Record each inherited entry's name, kind, and group — those are the three fields needed to detect candidate matches and to decide whether a per-repo proposal would shadow an inherited entry.
2. Read the existing tech_stack: block (refresh path)
When project/portfolio.yml already carries a non-empty tech_stack: block, parse it into three working sets:
existing_additions— every entry undertech_stack.additions[]existing_overrides— every record undertech_stack.overrides[]existing_regroup— every record undertech_stack.regroup[]
On a fresh capture, all three working sets are empty. The operator's confirmations in step 7 decide which existing entries persist, get edited, or get dropped; never silently preserve or remove an existing entry across a refresh.
3. Probe repository signals
Read the signal-source set in the order documented in references/signal-source-map.md, and read that file now to ground every kind/group/lifecycle proposal that follows: it carries the authoritative per-signal mapping table and is the only source the skill consults for "what does this signal imply".
The probe is read-only. Don't shell out to package managers, don't run installers, don't invoke the language runtime. A missing signal file is an absence, not an error.
For every signal hit, draft a candidate entry with: name (kebab-case, derived from the signal), kind (from the table), provisional group (from the table; refined in step 5), provisional lifecycle (from the table), version (only when the signal carries an unambiguous version per the spec's SHOULD; otherwise leave blank), and source_of_truth (the relative path of the signal that justified the candidate). The candidate's role and status are deferred until step 7 (operator confirmation) because they aren't signal-derivable.
4. Drop inherited matches from the candidate set
For every candidate whose name and kind both match an inherited entry from step 1, drop it from the candidate additions set unconditionally — per the schema spec's MUST NOT, a consumer never re-declares an inherited entry. Record the dropped match in a session-local "inherited-confirmed" list so step 7 can reassure the operator that the inherited entry is already part of their effective stack.
A candidate whose name matches an inherited entry but whose kind differs is a Critical finding — re-declaring under a different kind silently shadows inheritance. Surface it in step 7 with the recommended resolution: rename the candidate, or open a coordination PR against portfolio/tech-stack.yml to amend the global entry.
5. Propose group: per candidate
group: is a MUST on every entry (in both additions[] and inherited via the global manifest). For every surviving candidate from step 4, propose a group: value following the Deterministic group proposal rules in references/signal-source-map.md: auto-fill the deterministic kind → group mappings without prompting (docs, test, ci, dep-bot, build, package-manager, plugin-shaped framework, claude-code runtime), decide the lint-kind case from the source_of_truth path (docs/-scoped → documentation, source-tree → quality), and prompt the operator for the ask-the-maintainer cases (language, non-claude-code runtime, non-plugin framework, deploy-target, other, and any ambiguous lint). Heuristic guesses on the ask cases mislead and are forbidden by the spec.
6. Propose lifecycle: per candidate
lifecycle: is optional but SHOULD be proposed. Follow the Deterministic lifecycle proposal rules in references/signal-source-map.md: auto-fill the unambiguous kind → lifecycle mappings (test / lint / dep-bot / package-manager → development; ci / build / docs → build; deploy-target → runtime) and prompt for the ambiguous kinds (language, runtime, framework, other), accepting "skip" (leaves the field absent) as a legitimate answer per the SHOULD.
7. Interactive per-entry confirmation
Per the discovery spec's MUST, present every proposed delta to the maintainer before any write. The confirmation is a single round through three working sets:
- Proposed additions (from steps 3–6): for each candidate, present (a) the full field set (
name,kind,group,lifecycle,version,source_of_truth, plus the pendingroleandstatusslots), (b) the signal source(s) that justified the candidate, and (c) the explicit "this is a repo-specific addition, not inherited" classification. The operator answers per entry — accept, reject, or edit. On accept, the operator suppliesrole(one sentence) and confirmsstatus(defaultactive;experimentalis a legitimate alternative). - Proposed overrides — for every inherited entry the operator wants to suppress, build an override record with
name,inherit: false, and a non-emptyrationale. Empty rationale blocks the write. When the operator wants a different version of an inherited entry, surface the spec's two-step path (overrides:suppression PLUS a repo-specificadditions:replacement) — never edit the inherited entry's fields directly. - Proposed regroup — for every inherited entry whose repo-specific purpose differs from the portfolio default (for example
pythonused only by the MkDocs build pipeline in this repo), offer a regroup record withname, the newgroup:, and a non-emptyrationale. Refuse a no-op regroup (newgroupequals inheritedgroup) and refuse a regroup paired with an override on the samename(the override already removes the entry, so the regroup would be dead code).
Free-form additions (entries the operator declares despite no matching signal) are permitted under the spec's SHOULD, but the operator must acknowledge that portfolio-audit will Warning the missing signal. Record that acknowledgement verbatim in the entry's rationale with the marker phrase acknowledged-missing-signal: plus a one-sentence justification; the marker downgrades the audit finding to Suggestion.
Don't proceed to step 8 until every proposed addition, override, and regroup has been individually confirmed, edited, or rejected. An empty tech_stack: {} is a legitimate outcome and is written only after explicit confirmation — silent emptiness is forbidden.
8. Compose and write
Compose the final tech_stack: block from the three confirmed working sets. Before writing, run the local validation checklist in references/write-validation.md (mandatory-field, shadow-without-override, override-rationale, regroup, and enum checks); reject or block the write on any failure, surfacing the offending entry.
Then write project/portfolio.yml atomically. Preserve unrelated top-level keys (capabilities:, audiences:, peers: — whatever the existing manifest carries); only the tech_stack: key is rewritten. Re-parse the file after writing to confirm the result is valid YAML; on parse failure, restore the prior version and surface the parse error.
Confirm in the user's language with the path of the rewritten manifest, a per-section count (additions: N, overrides: M, regroup: K, inherited-confirmed P), and the reminder that opening a PR via pull-request-create is the next step — the skill stops at the write.
The skill MAY emit a "candidates not picked" log alongside the confirmation summary — signal-derived candidates the operator rejected in step 7, each with a one-phrase reason. The log is for the operator's audit awareness only; it is NOT committed to the repository.
Gotchas
tech_stack: {}is a legitimate empty result, not a missing block. A repository that uses the full inherited stack unmodified and has no repo-specific additions writestech_stack: {}after operator confirmation — never omit the key entirely. The audit treats an absenttech_stack:key as aCritical"manifest doesn't conform to the schema spec"; an empty mapping is the explicit "inherited as-is" affirmation. Don't shortcut by leaving the key out even when the confirmation result has zero additions, overrides, and regroups.- The
inherit:field is a fixed-literal, not a boolean knob. Everyoverrides[]record carriesinherit: falseexactly — the field is named explicitly for readability and to leave room for a future opt-in semantic without re-shaping the record (per schema §Inheritance semantics). Writinginherit: trueor omitting the field is a parse error against the schema. - Regroup vs. overrides-plus-additions is a one-or-the-other choice. A consumer who needs a different
groupvalue on an inherited entry usesregroup:. A consumer who needs a differentversion,role,kind, or any other field on the same entry usesoverrides:(to suppress) plusadditions:(to redeclare). Mixing both records for the samenameis aWarningaudit finding; the skill refuses to write the combination. - Free-form additions need the acknowledged-missing-signal marker. When the operator insists on declaring an entry that no signal supports (for example a documented deployment target that isn't yet wired into a workflow file), the skill writes
rationale: "acknowledged-missing-signal: <operator-sentence>". Without the marker phrase the audit emits a regularWarning; with the marker the audit downgrades toSuggestion. Don't reword the marker phrase —portfolio-auditrecognises the exactacknowledged-missing-signal:prefix. - The global manifest is read-only from this skill. Even when running inside
claude-shareditself, the skill never modifiesportfolio/tech-stack.yml. Promoting a repo-specific addition to portfolio-wide is a hand-curated PR against the global manifest, not a skill operation. When the operator asks the skill to "add this to the global stack", stop and route them to a hand-authored PR. - Refresh preserves operator-edited entries that survived a prior round. When
existing_additionsfrom step 2 contains entries the current signal probe wouldn't surface (for example a hand-addedkind: deploy-targetentry that doesn't have a signal class), the skill keeps presenting those entries in step 7 with their existing field set so the operator can re-confirm, edit, or drop them. Silently deleting them across a refresh would lose deliberate operator authoring.
Examples
- Read
examples/01-fresh-capture-empty-additions.mdwhen running a fresh capture on a project with no existingtech_stack:additions. - Read
examples/02-refresh-after-dep-bot-swap.mdwhen refreshing the tech-stack capture after Dependabot or Renovate has swapped a dependency. - Read
examples/03-deviation-with-override-and-regroup.mdwhen the project deviates from the portfolio baseline and you need to see how overrides and regroup records are authored.
Resumability
Per spec/claude/resumable-work/, this skill is resumable: true. State is persisted to .resume/tech-stack-capture/<run-id>.yml after every successful user-approval gate and after each named phase boundary. On re-invocation, scan that directory for files with status: in_progress whose inputs: snapshot matches the current invocation; if one matches, prompt the operator with Resume run <run_id> from phase <phase> (last checkpoint <last_checkpoint_at>)? [resume / start-new / discard]. The state-file envelope (schema_version, run_id, inputs, phase, decisions[], status, ...) and the fail-closed semantics on schema or YAML errors are load-bearing in the spec; don't duplicate those rules here.
Hard rules
- Never write
project/portfolio.ymlwithout an interactive per-entry confirmation round (steps 7) on every addition, override, and regroup. Skipping confirmation violates the MUST inspec/portfolio/tech-stack-discovery/§Discovery sequence per repository regardless of whether the result is technically a no-op. - Never modify the global manifest
portfolio/tech-stack.ymlfrom this skill, in any repository. The global manifest is hand-curated per the spec's MUST; automated detection is forbidden. - Never declare an
additions[]entry that matches an inherited entry on bothnameandkind. Drop inherited matches automatically in step 4; never present them as if they were repo-specific. - Never write an
overrides[]record with an empty or whitespace-onlyrationale. The spec's MUST requires a non-empty prose sentence; the audit treats empty rationale as aWarning. - Never write a
regroup[]record whose newgroupequals the inherited entry'sgroup(no-op regroup) or whoserationaleis empty. Both areWarning-grade audit findings — refuse the write upstream. - Never invent a signal hit. Every candidate entry traces back to a file the skill actually read. Free-form operator additions are permitted via the acknowledged-missing-signal marker; fabricating a signal source the skill didn't probe is forbidden.
- Never edit any field of an inherited entry other than via the schema spec's two mechanisms (
overrides[]to suppress,regroup[]to re-classify the group). The inherited entries'name,kind,role,version,status,lifecycle,since, andsource_of_truthstay portfolio-curated; the per-repotech_stack:block never mutates them. - Never commit a "candidates not picked" log to the repository. The log is session-local and exists only for the operator's audit awareness; persisting it would couple
portfolio-auditto in-band log files that aren't part of the schema. - When
spec/portfolio/tech-stack-discovery/orspec/portfolio/tech-stack/disagrees with this skill, the spec wins. Propose updating this skill rather than silently diverging.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

