| name | fstack-product |
| version | 0.7.0 |
| description | Create, inspect, switch, and bootstrap product profiles. A product profile is the per-product binding (verify, delivery, gates, owner-gated, board, done, stack, knowledge) that lets the invariant way of working run on a specific product. |
| allowed-tools | ["Bash","Read","Grep","Glob","AskUserQuestion"] |
| triggers | ["product profile","set up a product","bootstrap product","onboard product","switch product","which product am I on","show product profile"] |
/fstack-product
The product profile answers "what is this product and how is it delivered."
It is the peer of the builder profile (/fstack-profile, "how we work") and the
input to the way of working (WAY-OF-WORKING.md, the invariant core). Writes
target the active product. Switch first to edit a different one.
Fields: repo, verify, delivery, gates, owner_gated, board, done,
cost, stack, knowledge.
Preamble
_FSTACK_BIN=""
_skill_md="$HOME/.claude/skills/fstack-product/SKILL.md"
if [ -L "$_skill_md" ]; then _src="$(readlink "$_skill_md")"; _FSTACK_BIN="$(cd "$(dirname "$_src")/../bin" && pwd)"; fi
if [ ! -x "$_FSTACK_BIN/fstack-config" ]; then
for cand in "$HOME/Workspaces/fstack/bin" "$HOME/fstack/bin"; do [ -x "$cand/fstack-config" ] && _FSTACK_BIN="$cand" && break; done
fi
"$_FSTACK_BIN/fstack-config" exists || { echo "uninitialized. run /fstack"; exit 0; }
echo "ACTIVE PRODUCT: $("$_FSTACK_BIN/fstack-config" active-product)"
"$_FSTACK_BIN/fstack-product" list
If the user's intent reads like a different product, offer to switch or create
first. Ambiguity across products is the failure mode; always state which product
you are writing to.
Branch
- show / inspect
- list
- switch (use)
- create
- clone
- rename
- remove
- edit a field
- bootstrap (recon a repo and draft the profile)
- scaffold automation (hooks + workflows into the product repo)
1-3. Show / list / switch
"$_FSTACK_BIN/fstack-product" show
"$_FSTACK_BIN/fstack-product" show <key>
"$_FSTACK_BIN/fstack-product" list
"$_FSTACK_BIN/fstack-product" use <key>
4-7. Create / clone / rename / remove
"$_FSTACK_BIN/fstack-product" create <key> --label "<label>" --description "<desc>"
"$_FSTACK_BIN/fstack-product" create <key> --label "<label>" --clone-from <existing>
"$_FSTACK_BIN/fstack-product" rename <old> <new>
"$_FSTACK_BIN/fstack-product" remove <key>
After create, offer to bootstrap (branch 9).
8. Edit a field (writes to active product)
Confirm free-form input before writing (trust boundary). Scalars:
"$_FSTACK_BIN/fstack-config" set-product verify.command "<cmd>"
"$_FSTACK_BIN/fstack-config" set-product repo.remote "<org/repo>"
"$_FSTACK_BIN/fstack-config" set-product done "<definition>"
Arrays / objects:
"$_FSTACK_BIN/fstack-config" set-product-json owner_gated '["push","merge","deploy"]'
"$_FSTACK_BIN/fstack-config" set-product-json stack.database '["Postgres"]'
"$_FSTACK_BIN/fstack-config" set-product-json board.lease_fields '["Claim id","Lease until"]'
Gate values are the trigger description (or null to turn a gate off):
"$_FSTACK_BIN/fstack-config" set-product gates.security "any trust boundary: auth, untrusted content, secrets"
9. Bootstrap (recon -> draft)
The high-value path. Recon the target repo, propose every field, confirm, write.
Cold-start is the tax; a good draft pays it down.
- Confirm the repo root (default: cwd). Then gather signals, read-only:
_root="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
git -C "$_root" remote get-url origin 2>/dev/null
git -C "$_root" branch --show-current 2>/dev/null
ls "$_root"
sed -n '1,40p' "$_root/package.json" 2>/dev/null
git -C "$_root" log --oneline -20 2>/dev/null
ls "$_root/.github/workflows" 2>/dev/null
-
Infer and PROPOSE (do not write yet):
repo.remote / repo.vcs / repo.default_branch from git.
verify.command from the scripts block (a verify/check/test script,
a build + test chain). verify.e2e if a Playwright/Cypress config exists.
delivery.commits = conventional if the log looks conventional.
delivery.release if semantic-release / changesets present.
stack.* from dependencies and config files.
gates: turn on the dimensions the codebase warrants (security if there is
auth/untrusted input/edge code; design if there is UI; code by default).
owner_gated: default ["push","merge","deploy","delete","external-send"];
add legal/public-contract/spend if the product is outward-facing.
board: ask the user (provider + id); do not guess.
done: the standard definition unless the user overrides.
-
Show the full proposed profile. Batch open questions into ONE
AskUserQuestion round (board provider/id, verify command if ambiguous,
owner-gated additions), each with a recommended default. Then write with
set-product / set-product-json, and stamp:
"$_FSTACK_BIN/fstack-config" set-product declared_at "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
"$_FSTACK_BIN/fstack-product" show
- Tilt defaults with the active builder profile:
"$_FSTACK_BIN/fstack-profile" calibrate stack. High test_rigor ->
verify.green_required on + more gates; low risk_tolerance -> wider gate
set; low autonomy -> more owner-gated entries.
10. Scaffold automation
Copy the hook + workflow templates into the product repo and wire them. This is
what makes the way of working enforced, not just described.
_tmpl="$(cd "$_FSTACK_BIN/.." && pwd)/templates"
_dest="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
mkdir -p "$_dest/.claude/hooks"
cp "$_tmpl"/hooks/*.sh "$_dest/.claude/hooks/" && chmod +x "$_dest/.claude/hooks/"*.sh
echo ".fstack-verify-ok" >> "$_dest/.gitignore"
Then merge templates/hooks/settings.snippet.json into
$_dest/.claude/settings.json (read both, merge the hooks block, confirm
before writing). Point the user at templates/workflows/ for the Workflow
scripts (epic-close, review-verify, migrate-sweep) they invoke via the Workflow
tool with product args. Confirm before any write under the product repo.
Voice
Short. Direct. Always name the active product before writing. Confirm free-form
values before mutating. Never guess the board id. Both profiles compose: the
product says what must be true; the builder says how strictly.