Good Planning
Security Notice
This extension includes AI agent skills that can modify AI assistant behavior. Review the skill files before installing.
Good-planning model that operationalizes Felipe Bovolon's "Good Planning Bad Planning" four-layer architecture as queryable swamp state. Strategy chooses; planning commits — this model holds the commitment.
Article: https://bovolon.substack.com/p/good-planning-bad-planning
A plan is not a slide deck. The article's thesis: the real plan is the pattern of commitments the organization has actually funded, sequenced, protected, and agreed to review. This model makes those commitments first- class state with explicit assumptions, signposts, tripwires, ceiling trigger points, and a pullback ladder — so the plan can be evaluated and revised on a cadence rather than executed-as-written until reality breaks it.
Four Layers (from the article)
- Layer 1 — Assumption: what the plan believes about the world. Each assumption has impact, vulnerability, and a signpost.
- Layer 2 — Allocative: what is actually funded and protected. Targets, forecasts, and allocations are tracked separately (Beyond Budgeting).
- Layer 3 — Coordinative: how commitments interlock.
Captured via
dependsOnon each commitment. - Layer 4 — Adaptive: how the plan revises.
Ceiling discipline (first-binding crux + trigger formula) and
floor discipline (signposts → tripwires → pre-authorized actions
- pullback ladder + max tolerable loss).
State Machine
drafted ──[commit]──> committed (gated: all four layers populated)
committed ──[monitor]──> monitoring
monitoring ──[evaluate]──> monitoring (read signposts, update layer state)
monitoring ──[trigger]──> adapting (tripwire fired or ceiling crossed)
adapting ──[adapt]──> committed (pullback or option exercised)
adapting ──[revise]──> drafted (assumption broken — re-plan)
committed ──[archive]──> archived
monitoring ──[archive]──> archivedcommit is the gate the article calls for: it refuses to leave drafted
unless every layer is materially populated, including the six properties
on every commitment (owner, resource, time, dependencies, review rule,
consequence-if-changed) and at least one tripwire on the floor side.
Methods
start— create a draft plan with strategicChoice + horizonadd_assumption— record an assumption with impact / vulnerability / signpostadd_commitment— record a commitment or hypothesis (six-property gate)add_allocation— record protected budget per priority (Layer 2)add_ceiling— record a first-binding crux + lead time + signpostadd_tripwire— record a signpost threshold + pre-authorized actionset_pullback_ladder— ordered list of cuts (what to cut first)set_loss_budget— sunk + shutdown + liabilities + working-capital + tailcommit— gate; transitions drafted → committedmonitor— committed → monitoringevaluate— read a signpost; updates assumption/tripwire/ceiling statetrigger— explicit transition into adapting (action required)adapt— record adaptation taken; back to committedrevise— assumption broken; back to draftedarchive— terminalhydrate— write a compact governability scorecard summaryaudit— answer the four diagnostic questions (one per layer)
2026.08.02.1
Real-fix wave for the eight GP-1..GP-8 bugs pinned by the prior release's
adversarial suite (same wave as sibling extensions seadex and
victoriametrics, both already at 2026.08.02.1). Model version bumped
2026.07.16.2 → 2026.08.02.1 with an upgrades[] entry; resource schema
unchanged (upgradeAttributes: (old) => old).
- GP-1 fixed (MEDIUM) —
start()now reads the existingcurrentresource before writing. If a plan already exists it throws (naming itsstate/planVersion) instead of silently wiping it — pass the newforce: trueargument to intentionally discard an existing plan and start fresh. - GP-2 fixed (MEDIUM) —
adapt()now resets the tripwire matchingtriggeredByback to"dormant"when it was"fired", so a stale re-trigger()afteradapt()→monitor()correctly rejects with "No fired tripwire" until a freshevaluate()fires it again. - GP-3 fixed (MEDIUM) —
commitmentSatisfiesSixProperties'sbyDatecheck no longer relies onDate.parse's engine-defined leniency. It now requires a strict ISO-8601 calendar date or date-time (z.iso.date()/z.iso.datetime());"2026"and"next quarter"are both rejected,"2026-09-01"still accepted. - GP-4 fixed (LOW) —
evaluate()now rejects a mismatched-layer payload (e.g.timeToCruxWeeksfor a signpost with no matching ceiling) instead of silently dropping it, naming the offending field and the layer it needs. - GP-5 fixed (LOW) —
commitGateReport,governabilityScore, andauditDiagnosticQuestions.layer1Visiblenow share onehasLiveAssumptionpredicate that excludesstate:"broken"assumptions. A plan whose every assumption is broken now fails the commit gate and scores Layer-1 absent; a plan with at least one non-broken assumption still scores it present. - GP-6 fixed (LOW) —
tripwire.pullbackRungis now bounds-checked against a non-emptypullbackLadder:add_tripwirerejects a rung past the current ladder length, andset_pullback_ladderrejects a ladder too short for an already-referenced rung. A rung recorded before any ladder is set (deferred) andpullbackRung:0against an empty ladder both stay legal — required by the frozen contract fixture. - GP-7 fixed (LOW) — every
add_*method (add_assumption,add_commitment,add_allocation,add_ceiling,add_tripwire) is now idempotent: a structurally-identical repeat call is a no-op (still returns a handle); a call differing in even one field still appends normally. - GP-8 fixed (LOW) —
computeTriggerPointandcomputeMaxTolerableLossnow throw on non-finite (NaN/Infinity) inputs instead of propagating them through the arithmetic. The method-arguments zod boundary already rejected both for plainz.number()fields; these two guards close the gap for direct calls to the exported pure helpers. - Rewrote the eight GP-* pins in
good_planning_adversarial_test.tsfrom "asserts the buggy behavior" to "asserts the fixed behavior", and added idempotence (GP-7),force:true(GP-1), strict-date (GP-3), and ladder-bounds (GP-6) positive-path tests alongside them. The frozen contract suitegood_planning.test.tsand themethods/coverage/propertysuites are unchanged (traced call-by-call; every exercised path uses matching-layer payloads, distinctadd_*args, finite numbers, and a fresh-contextstart). quality.yaml: re-stamped from a liveswamp extension qualityrun; dropped the prior release's "byte-frozen / no behavior change" wording now that this release ships real fixes. All five suites staypresent; ratchet stays100/"Grade A".
| Argument | Type | Description |
|---|---|---|
| strategicChoice | string | The where-to-play / how-to-win sentence in one line |
| horizon | string | e.g. '3y', '12m' |
| notes? | string | |
| force | boolean | Set true to intentionally replace an existing plan. Without |
| Argument | Type | Description |
|---|---|---|
| statement | string | |
| signpostName | string | |
| signpostExpr? | string | |
| lastReading? | string |
| Argument | Type | Description |
|---|---|---|
| description | string | |
| owner | string | |
| budgetUsd | number | |
| byDate | string | |
| dependsOn | array | |
| reviewCadence | string | |
| consequenceIfChanged | string |
| Argument | Type | Description |
|---|---|---|
| priority | string | |
| protectedBudgetUsd | number | |
| target? | string | |
| forecast? | string | |
| raidLog | array |
| Argument | Type | Description |
|---|---|---|
| crux | string | |
| leadTimeWeeks | number | |
| safetyMarginWeeks | number | |
| signpostName | string | |
| optionPremiums | array | |
| lastTimeToCruxWeeks? | number | |
| lastTriggerPointWeeks? | number |
| Argument | Type | Description |
|---|---|---|
| signpostName | string | |
| thresholdExpr | string | |
| preAuthorizedAction | string | |
| pullbackRung? | number | |
| lastReading? | string |
| Argument | Type | Description |
|---|---|---|
| rungs | array |
| Argument | Type | Description |
|---|---|---|
| sunkCostUsd | number | |
| shutdownCostUsd | number | |
| committedLiabilitiesUsd | number | |
| workingCapitalUnwindUsd | number | |
| tailProvisionsUsd | number |
| Argument | Type | Description |
|---|---|---|
| signpostName | string | |
| reading | string | Observed value, free-form string |
| timeToCruxWeeks? | number | If reading impacts a ceiling: observed weeks until crux. |
| Argument | Type | Description |
|---|---|---|
| signpostName | string | |
| reason | string |
| Argument | Type | Description |
|---|---|---|
| triggeredBy | string | Signpost name or ceiling crux that caused the adapt |
| actionTaken | string | |
| reason | string | |
| reading? | string | |
| exercisedCeilingCrux? | string | If the action exercised a ceiling option, name the crux to mark it |
| Argument | Type | Description |
|---|---|---|
| reason | string | |
| brokenAssumptions | array |
| Argument | Type | Description |
|---|---|---|
| reason | string |
Resources
Release 2026.07.16.2 — align model versions with manifests
Maintenance release across the @magistr extensions. For most packages this
carries no functional change: the only edit is the model's version: field,
brought back in line with its manifest version so the published model type
version and the package version no longer drift.
Functional changes in this release are limited to:
anime-cron: normalizeTitle now strips a ": subtitle" suffix and a trailing parenthesized year before comparison, fixing dedup false-misses where the torrent title carries a subtitle or year that the AniList romaji does not.
arckit: first publish. Standalone ArcKit port — a 12-phase architecture governance state machine with 65 bundled templates, driven by a bundled skill.
Also tracks three extensions (kaiten, observability-agent, music-library) that previously existed only as untracked working-tree directories, recovered from stashes.
Added 1, removed 1 models. Added 1 skills
2026.05.01.1 — Add article link to extension description
Surface the source article URL directly in the manifest description so the swamp.club extension page links to it without forcing readers into the README:
Article: https://bovolon.substack.com/p/good-planning-bad-planning
The link was already present in README.md, SKILL.md, and the model source file as a citation, but missing from the manifest description that drives the registry summary card. No code or schema changes — this is a metadata-only release.
- Has README or module doc2/2earned
- README has a code example1/1earned
- README is substantive1/1earned
- Most symbols documented1/1earned
- No slow types (deprecated)1/1earned
- Dependencies pass trust audit2/2earned
- Has description1/1earned
- Platform support declared (or universal)2/2earned
- License declared1/1earned
- Verified public repository2/2earned