/purpose-properties
Derive the binding properties your why/how/what impose on everything below them, so no solution can silently contradict your own product definition. Retrofit entry point for projects that started before v0.120.0; also the re-derive path when why/how/what change and every stance
Claude Code
$ npx -y skills add haabe/mycelium --skill purpose-properties --agent claude-code
Codex
$ npx skills add haabe/mycelium --skill purpose-properties -a codex -y
Cursor
$ npx skills add haabe/mycelium --skill purpose-properties -a cursor -y
Gemini CLI
$ npx skills add haabe/mycelium --skill purpose-properties -a gemini-cli -y
GitHub Copilot
$ npx skills add haabe/mycelium --skill purpose-properties -a github-copilot -y
OpenCode
$ npx skills add haabe/mycelium --skill purpose-properties -a opencode -y
Windsurf
$ npx skills add haabe/mycelium --skill purpose-properties -a windsurf -y
SKILL.md
purpose-properties.SKILL.mdname: purpose-properties
description: "Derive the binding properties your why/how/what impose on everything below them, so no solution can silently contradict your own product definition. Retrofit entry point for projects that started before v0.120.0; also the re-derive path when why/how/what change and every stance below them goes stale."
metadata:
instruction_budget: "21"
framework_dependency: "mycelium"
framework_dependency_note: "This skill is designed to run within the Mycelium framework (https://github.com/haabe/mycelium). Standalone use will skip the canvas state, theory gates, and harness behavior the skill assumes. Install: /plugin install mycelium@haabe-mycelium."
Purpose Properties Skill
Retrofit and re-derive entry point for `purpose.yml#purpose_properties`. **For new projects this runs inside `/mycelium:start` Step 3b.** Use this skill when:
- The project existed before **v0.120.0** and has no `purpose_properties` (the retrofit case — every
project created before that release, since `/mycelium:start` Step 4 exits for already-initialized projects and never reaches the extraction).
- `why`, `how` or `what` changed, so `derived_from_hash` no longer matches and **every stance below
it is superseded** (the drift case — this is the one that matters most and the easiest to skip).
- A property list exists but the user wants to revisit which properties are `binding`.
Full contract: https://github.com/haabe/mycelium/blob/main/docs/purpose-stance.md (it lives in the repository, not in the installed plugin).
Step 1: Read the current state and say which case this is
Read `purpose.yml`. Then say plainly which of these you are in, because the three have different consequences and the user should not have to infer it:
- **No `purpose_properties`** → retrofit. Nothing below has ever been checked against the purpose.
- **Hash mismatch** → drift. Report it as *"your purpose changed after these were derived, so every
`purpose_stance` below them was reasoned under a definition you have since changed."* This is the state that quietly invalidates work; name it in those terms.
- **Hash matches** → nothing to do. Report the property count and stop. Do not re-derive for tidiness.
Step 2: Attempt extraction, and classify what fails
For every element of `why`, `how` and `what`, ask: **can I name a specific solution that would CONTRADICT this?**
- **Yes** → candidate property. Record `property`, `verbatim` (their words, not yours), `source`, and
the contradicting solution in `contradicted_by`.
- **No** → **do not force one.** Quality adjectives — *secure, accessible, fast, simple, delightful,
robust* — yield nothing checkable, because every candidate solution claims to satisfy them.
**Measured 2026-08-23, blind:** *"accessible and secure"* produced **no** checkable property, while five abstract framework principles produced clean ones. **The axis is not abstract vs concrete — it is quality adjective vs structural claim.** Do not treat concrete-sounding words as safe.
Step 2a: Screen for quality adjectives BEFORE trusting your own refusal
**DO NOT RELY ON NOTICING.** Step 2 says a quality adjective yields nothing checkable and asks you to decline. The evidence that an extractor actually declines is **one blind run, one model family** — the 2026-08-23 test, where the extractor returned NONE for *"accessible and secure"* unprompted. That result is real and it is thin, and this skill runs under model families that test never touched, in runtimes where no hook fires to catch the difference. **A model that does not refuse produces a confident property, marks it binding, and creates a stance field that every solution answers `preserves` forever — populated, green, and meaningless.** The mechanism's own failure mode, at its entry point.
So the screen is a rule, not a judgement:
**TRIGGER LIST — if an element contains any of these words, it routes to Step 3 REGARDLESS of whether you extracted something from it:**
> secure · safe · private · accessible · usable · intuitive · simple · easy · fast · performant · > scalable · reliable · robust · flexible · modern · seamless · delightful · high-quality · > best-in-class · efficient · powerful · lightweight
**Extracting a property from one of these words is not evidence the word was checkable.** It is the predicted failure. Route it, let the builder supply the standard, and record what they say.
**AND THE GENERAL TEST, for words the list does not carry** (it cannot be complete, and treating it as complete is the next version of this bug):
> **Would every plausible competing solution ALSO claim to satisfy this?** > If yes, it is a quality adjective, whatever it sounds like. Route it.
*"Secure"* fails that test — nobody proposes an insecure login. *"Anonymous"* passes it — a solution requiring an account plainly does not claim anonymity. **Note that the concrete-sounding word is the one that fails.** The axis is never how technical the word looks.
**WHAT IS STILL UNTESTED, stated so nobody reads the list as coverage:** whether a builder actually answers the Step 3 prompt. The 2026-08-23 run exercised extraction only — no builder was asked anything — so the recovery path has evidence for its necessity and none for its effectiveness.
Step 2b: Check the ALTITUDE of every candidate before you record it
**A property must sit at the altitude where violation is meaningful.** Ask, of each candidate:
> **What would have to be true for this to be violated — a single move, or a design choice?**
- **A design choice** → it is a property of the product. Record it.
- **A single move** → **you have extracted a rule about BEHAVIOUR, not a property of the product.
Do not record it.** A property that can be violated by one sentence turns the stance field into a footnote requirement, and a check people must satisfy per action is one they mute.
**WORKED EXAMPLE, and it is why this step exists.** From *"Theory-guided dec
Read more
name: purpose-properties description: "Derive the binding properties your why/how/what impose on everything below them, so no solution can silently contradict your own product definition. Retrofit entry point for projects that started before v0.120.0; also the re-derive path when why/how/what change and every stance below them goes stale." metadata: instruction_budget: "21" framework_dependency: "mycelium" framework_dependency_note: "This skill is designed to run within the Mycelium framework (https://github.com/haabe/mycelium). Standalone use will skip the canvas state, theory gates, and harness behavior the skill assumes. Install: /plugin install mycelium@haabe-mycelium."
Purpose Properties Skill
Retrofit and re-derive entry point for `purpose.yml#purpose_properties`. **For new projects this runs inside `/mycelium:start` Step 3b.** Use this skill when:
- The project existed before **v0.120.0** and has no `purpose_properties` (the retrofit case — every
project created before that release, since `/mycelium:start` Step 4 exits for already-initialized projects and never reaches the extraction).
- `why`, `how` or `what` changed, so `derived_from_hash` no longer matches and **every stance below
it is superseded** (the drift case — this is the one that matters most and the easiest to skip).
- A property list exists but the user wants to revisit which properties are `binding`.
Full contract: https://github.com/haabe/mycelium/blob/main/docs/purpose-stance.md (it lives in the repository, not in the installed plugin).
Step 1: Read the current state and say which case this is
Read `purpose.yml`. Then say plainly which of these you are in, because the three have different consequences and the user should not have to infer it:
- **No `purpose_properties`** → retrofit. Nothing below has ever been checked against the purpose.
- **Hash mismatch** → drift. Report it as *"your purpose changed after these were derived, so every
`purpose_stance` below them was reasoned under a definition you have since changed."* This is the state that quietly invalidates work; name it in those terms.
- **Hash matches** → nothing to do. Report the property count and stop. Do not re-derive for tidiness.
Step 2: Attempt extraction, and classify what fails
For every element of `why`, `how` and `what`, ask: **can I name a specific solution that would CONTRADICT this?**
- **Yes** → candidate property. Record `property`, `verbatim` (their words, not yours), `source`, and
the contradicting solution in `contradicted_by`.
- **No** → **do not force one.** Quality adjectives — *secure, accessible, fast, simple, delightful,
robust* — yield nothing checkable, because every candidate solution claims to satisfy them.
**Measured 2026-08-23, blind:** *"accessible and secure"* produced **no** checkable property, while five abstract framework principles produced clean ones. **The axis is not abstract vs concrete — it is quality adjective vs structural claim.** Do not treat concrete-sounding words as safe.
Step 2a: Screen for quality adjectives BEFORE trusting your own refusal
**DO NOT RELY ON NOTICING.** Step 2 says a quality adjective yields nothing checkable and asks you to decline. The evidence that an extractor actually declines is **one blind run, one model family** — the 2026-08-23 test, where the extractor returned NONE for *"accessible and secure"* unprompted. That result is real and it is thin, and this skill runs under model families that test never touched, in runtimes where no hook fires to catch the difference. **A model that does not refuse produces a confident property, marks it binding, and creates a stance field that every solution answers `preserves` forever — populated, green, and meaningless.** The mechanism's own failure mode, at its entry point.
So the screen is a rule, not a judgement:
**TRIGGER LIST — if an element contains any of these words, it routes to Step 3 REGARDLESS of whether you extracted something from it:**
> secure · safe · private · accessible · usable · intuitive · simple · easy · fast · performant · > scalable · reliable · robust · flexible · modern · seamless · delightful · high-quality · > best-in-class · efficient · powerful · lightweight
**Extracting a property from one of these words is not evidence the word was checkable.** It is the predicted failure. Route it, let the builder supply the standard, and record what they say.
**AND THE GENERAL TEST, for words the list does not carry** (it cannot be complete, and treating it as complete is the next version of this bug):
> **Would every plausible competing solution ALSO claim to satisfy this?** > If yes, it is a quality adjective, whatever it sounds like. Route it.
*"Secure"* fails that test — nobody proposes an insecure login. *"Anonymous"* passes it — a solution requiring an account plainly does not claim anonymity. **Note that the concrete-sounding word is the one that fails.** The axis is never how technical the word looks.
**WHAT IS STILL UNTESTED, stated so nobody reads the list as coverage:** whether a builder actually answers the Step 3 prompt. The 2026-08-23 run exercised extraction only — no builder was asked anything — so the recovery path has evidence for its necessity and none for its effectiveness.
Step 2b: Check the ALTITUDE of every candidate before you record it
**A property must sit at the altitude where violation is meaningful.** Ask, of each candidate:
> **What would have to be true for this to be violated — a single move, or a design choice?**
- **A design choice** → it is a property of the product. Record it.
- **A single move** → **you have extracted a rule about BEHAVIOUR, not a property of the product.
Do not record it.** A property that can be violated by one sentence turns the stance field into a footnote requirement, and a check people must satisfy per action is one they mute.
**WORKED EXAMPLE, and it is why this step exists.** From *"Theory-guided dec
Mycelium won't make your idea good. It keeps you and your agent honest about whether it is, from first idea to market. Built on Claude Code, where the gates are structural. The files and skills port to opencode, Codex and Cursor. Outcome over output.
Other skills on mycelium.
More skills from other plugins.
brainstorming
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…
ask-matt
Ask which skill or flow fits your situation. A router over the skills in this repo.
Questions about purpose-properties.
- Which coding agents can use purpose-properties?
- purpose-properties installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.

