ways

FAQ

ways vs skills vs steering, required slots, unknown vs fail, and other recurring questions.

Why declare vcs-host: github when my git remote already says GitHub?

Because the declaration isn't there to tell ways what you use. It's there so the way's author can write the skill without naming a vendor.

Detection could tell your machine that you're on GitHub. It can't help the person writing the way, who has never seen your repo and needs open a PR on the vcs-host to be a sentence they can write once. Remove the slot and that author is back to shipping one way per toolchain.

The second reason is that a guess lives on one laptop. A binding in ways.yaml is committed, so your teammates and CI validate against the same choice instead of each adapting to whatever their own environment happens to look like.

In practice this is one line, set once, and often just a confirmation of the way's default. Full detail in Slots & bindings.

Do I actually need requires and doctor?

If your team is four people who all have git and gh installed and the MCP servers already wired, honestly: not much. You'll run doctor once, it'll pass, and you'll move on.

It earns its place when the environment isn't a given. Onboarding a developer onto a locked-down corporate machine where nothing is installed, joining a client's project with a different security stack, or a regulated environment where "install whatever you need" isn't an option. In those cases the alternative is discovering a missing CLI or MCP server halfway through a flow, which is how a twenty-minute setup becomes a three-day one.

So treat it as a recipe for the people who come after you, not as ceremony for the person who already has everything.

ways vs skills vs steering?

They're layers rather than competitors: ways delegates to the other two.

ToolUnitJob
npx skillsa skill (SKILL.md)install one capability into your agents
steering.shrules/context filesdistribute AI context, converted per agent
waysa gated process + its whole contractdeclare, validate, and install the way of working that uses skills and rules

If you need one prompt-capability: skills. If you need shared conventions in every agent: steering. If you need "this is how our team ships — gates, docs, tools — and I want the environment proven before anyone runs it": ways.

How do I update a way — and how do I know a new version exists?

Bump the pin and re-add:

npx ways.sh add github:org/way#v1.3.0   # was #v1.2.0

add re-acquires at the new ref, re-validates (schema + conformance), re-scans with Ways Shield, and asks for approval again — trust is bound to the content digest, so changed content never rides an old yes. The lock records the new pin, and every teammate picks it up with plain ways install on their next pull; CI does the same.

What ways does not do yet is discovery: it won't tell you that a new version was published. Watch the way's repo (releases or tags) the way you would any dependency. A version-notification / update flow is planned — the lock already carries everything it needs.

Way vs WayFamily?

A Way is one gated flow — one phase model, its gates, the documents it generates, the skills that drive it, and the slots it needs. A WayFamily is a set of related ways installed together, plus the payload they share (skills, rules, slots, requires) — and it has no flow of its own. Ship a feature flow and a bug flow (different gates) under one identity as a family; ways add <family> installs all members (or a --members subset) in one approval, and each member stays a valid Way you can install on its own. Full detail in Ways & families.

What are hooks?

spec.hooks[] lets a way declare hook packs — auto-executing event handlers (e.g. a PreToolUse guard that blocks git commit while a gate is unapproved). They're placed by hooks.sh, approved with full clarity (each pack expands to its event → command lines before you say yes), pinned in the lock, and shown by ways list --components. See Authoring.

Why did ways add refuse my way?

The usual suspects, in order: not schema-valid (ways validate shows the errors), not conformant (missing hard user gate, non-namespaced name — see Gates & conformance), a declared file missing from the bundle, a coexistence conflict with an already-installed way (the error names both ways and the resolution; --force overrides knowingly), or a Ways Shield block — the message starts with refused by ways shield and names the file and the finding.

refused by ways shield — what now?

Shield scans the content a way is about to place, right before the approval gate. A block means it found a well-known credential shape (an AWS/GitHub/Slack/Stripe/OpenAI/Anthropic/Google token, a private-key block) inside a bundled skill, hook, rule, bin/, or .mcp.json — and it refuses with or without --yes, because a leaked key is not something to click past.

The fix is almost always to remove the credential from the way's content. If it's a genuine false positive — a docs page quoting a vendor's own published example key — the author can mark that line shield:allow (or shield:allow:<rule-id> to scope it to one rule). --force overrides the whole run, knowingly and logged; reach for it last. Warn-level findings (an unpinned MCP server, a hook command chaining a second command) don't refuse by default — they're shown in the plan, and --strict promotes them to blocking. Full detail in Ways Shield.

We already approved this way — why is install still scanning it?

Because provenance trust and content safety are different questions. An approvedDigest that matches proves the content is byte-identical to what a human approved; it doesn't prove that content is safe — and a way approved before Shield existed was never checked at all. So ways install scans every locked way unconditionally, including the ones that skip the re-approval prompt (the common fresh-clone case). It costs a static scan of already-local files; there's no network call and nothing executes.

How do my teammates (and CI) get the exact same ways?

They run ways install. add is for acquiring a new way (resolve a ref, approve it, write it into ways.lock); install reproduces the ways already declared in the committed ways.yaml + ways.lock — every way at its locked sha, digests verified, external skills at their pins. It's the npm ci of ways. The approval travels in the lock (approvedDigest), so byte-identical content is never re-prompted, and content that doesn't match the lock is refused rather than silently installed. In CI, use ways install --frozen: anything not locked (or drifted) becomes a hard failure, so the pipeline only installs what a human already approved.

Can I override a required slot?

You can bind it to any impl, and the wizard even lets you skip it after an explicit confirmation. What you can't do is demote its requiredness: doctor fails an unbound required slot, with no consumer-side flag to silence it. Author-side, mark slots required: false when they're genuinely optional.

What's the difference between unknown and fail in doctor?

fail = required and verified missing/broken. unknown = present but unverifiable — a bound slot with no Binding profile, a check command that didn't run because the way isn't trusted yet. doctor never converts ignorance into a pass or a fail; use --strict in CI to treat unknown as failure.

Why does doctor say "run with --run-checks on a trusted way"?

The way's declared check commands are executable content, so they only auto-run when the way is trusted: approved at its current content digest in ways.lock. If you edited the installed content (or never approved), re-run ways add to re-approve — or force one run with --run-checks.

Where do Binding profiles come from?

Three places, in precedence order: the project's catalog (ways.yaml → contracts:), then the way's own bundle (bindings/), then the shared catalog a namespace points at (spec.contracts). First match wins, so your repo can register an in-house impl without forking the way. Catalogs are acquired and pinned like a way (in ways.lock under contracts), and because a Binding contributes check commands that doctor runs, they're disclosed in the ways add approval plan. Inspect what resolved with ways contracts. Full detail in Reference: contracts and catalogs.

My binding shows "no Binding profile found"

No kind: Binding artifact for that {contract, impl} pair resolved from any tier — not the project catalog, the way's bundle, or the shared catalog. The binding still works (it's recorded, doctor reports the slot unknown); to get pass, ship the profile in the way bundle or register a catalog that provides it — see Resolving contracts.

Where does a way store its progress?

In a single .ways/state.json per worktree or branch: the phase, gate status, and the documents each phase produced. It's what lets a flow resume and lets tooling see what's going on. Analytical runs (assessment, threat model, docs) use the same file with a namespaced flow. Full shape in State files.

Can I see that progress in my editor?

Yes — Lens (ways-lens) is a pure reader of .ways/state.json that docks a panel in your IDE: the phase stepper, gates (with PR links), step progress, and clickable document chips for the current worktree's branch. It ships for VSCode and its forks (Cursor, Kiro, VSCodium) today; JetBrains and Visual Studio are next. It never writes state and never approves a gate — the flow writes, you commit, Lens shows.

What should I add to .gitignore?

.claude/ and .agents/ — placement output from skills.sh / steering / hooks.sh (plus, for .claude/, your agent's own local settings). Every bit of it is regenerated from the lockfiles by ways install, so it's exactly as disposable as node_modules. incu-way-init adds both automatically if you're using the incu-way skill set.

The lockfiles stay committed — they're the source of truth, not the ignored output: ways.lock always, plus skills-lock.json when a way places skills and steering-lock.json when it places rules/knowledge.

.ways/ is the one exception to watch: don't blanket-ignore it. .ways/state.json holds a work-item's live phase/gate state and has to stay tracked so the flow can resume on that branch. If you also use the ways CLI, ignore only its cache — .ways/cache/ — never the whole directory.

Is there a registry?

Yes — registry.ways.sh. It's a registry, not a marketplace: ways stay hosted in their own git repos, and the registry indexes, validates, and renders them against the ways/v1alpha1 contract — so you can browse the catalog and see how a way runs (its phases, gates, produced documents, capability slots, and required tooling) and its validation tier before you ways add it. It also exposes a read-only resolve API the CLI uses to turn a name into a pinned git ref. You still install straight from a local path or git ref too — the registry never hosts artifacts. (Publishing UI and voting are on the roadmap, not built yet.)

On this page