Investigation Notes
Before this change the repo had no durable marketing capability. Cycle state — the runbook, the announced-features ledger, the cycle records — existed only as git-ignored files on one workstation, and the marketing-cycle formula existed only in that workstation's local store. Factories run in disposable containers: anything uncommitted dies with the container, so the ledger (the cross-run memory that tells a cycle what has already been announced) could not survive between runs, and no other clone or container could run a marketing cycle at all. An earlier attempt to land this content reached main without review and was force-rewound; this issue and PR #90 are the properly gated re-land.
PR #90 introduces the complete capability: committed cycle state under .marketing/, the generic (repo-agnostic) marketing-cycle formula in both its runtime and embed locations, and the generated first-class agent.
Affected Layers & Files
Cycle state (.marketing/ — committed, following the .designs/ pattern)
approach.md — the operator-signed runbook: operator identity, channels with homepage allowlist, voice profile, claim-verification map, Standing Assets declarations, explicit Privacy-Decision: COMMITTED, and the sign-off line
announced-ledger.md — cross-run record of what has been announced, where, and when; also carries the untold-features backlog
cycle-1-audit.md, cycle-1-log.md, cycle-1-story.md, cycle-1-report.md, cycle-1-publish-checklist.md — cycle-1 records (log and story are labeled RECONSTRUCTED: the checks ran live 2026-07-11/12; the files were assembled afterward in the formula's artifact format)
cycle-1-linkedin.md, cycle-1-medium.md — the two published drafts (content already public)
architecture-diagram.png, social-preview.png, social-preview.svg — declared standing assets
Formula (declarative workflow, 23 steps)
.agentfactory/store/formulas/marketing-cycle.formula.toml — runtime copy
internal/cmd/install_formulas/marketing-cycle.formula.toml — embed copy (ships in the af binary)
Structure: first-run bootstrap that generates the runbook by operator interview and holds for sign-off; four human gates (story approval, draft approval, Tier A merge, publish); five evidence-logged checklist gates that write VERDICT lines to the cycle log; an artifact-manifest gate in cleanup that fails any file tracing to no formula step and no Standing Assets declaration; operator communication via GitHub issues and PR comments (agent mail stays agent-to-agent); data-not-directive guards on untrusted input; homepage-URL validation against the runbook's allowlist.
Agent (first-class, generated by af formula agent-gen from formula v2)
internal/templates/roles/marketing-cycle.md.tmpl — embedded role template, so the agent identity survives context compression
.agentfactory/agents/marketing-cycle/CLAUDE.md — workspace persona
.agentfactory/agents/marketing-cycle/.claude/settings.json — hook configuration
.agentfactory/agents.json — registration
Additional Context
- The formula is generic by design: everything repo- or operator-specific (voice, channels, target phrases, verification paths, allowlists) lives in the runbook, which a first run generates by interview. This repo's runbook is the first instance; a different repo bootstraps its own.
- Privacy is an explicit operator decision recorded in the runbook, then enforced against git state — never inferred from ambient ignore rules. Gotcha for future readers:
git check-ignore silently skips already-tracked files unless --no-index is used; the formula's enforcement accounts for this.
- The plan-era drafts that will never ship (Show HN, Reddit, awesome-list submission plans) are deliberately absent per operator decision — "didn't happen and aren't going to happen." The manifest gate flags any such unaccounted file in future cycles.
- The runbook instructs agents that only the operator merges PRs; the formula's delivery step opens the PR and holds.
Acceptance Criteria
- After merge, a fresh clone or newly built container contains the runbook, ledger, and cycle-1 records; a subsequent cycle can determine what has already been announced with no state from the original workstation.
- A factory built from this repo can discover and instantiate the marketing-cycle formula, and the generated agent's identity survives context compression.
- A cycle run against a repo with no runbook stops at bootstrap and waits for operator sign-off rather than proceeding.
- No content under the operator's name is ever published by the agent; every such artifact waits at a human gate, and post-merge history shows operator merges only.
- Every file in
.marketing/ is accounted for: it traces to a formula artifact or a Standing Assets declaration.
- Template-regen CI passes with the committed role template (template and formula stay in sync).
Investigation Notes
Before this change the repo had no durable marketing capability. Cycle state — the runbook, the announced-features ledger, the cycle records — existed only as git-ignored files on one workstation, and the marketing-cycle formula existed only in that workstation's local store. Factories run in disposable containers: anything uncommitted dies with the container, so the ledger (the cross-run memory that tells a cycle what has already been announced) could not survive between runs, and no other clone or container could run a marketing cycle at all. An earlier attempt to land this content reached main without review and was force-rewound; this issue and PR #90 are the properly gated re-land.
PR #90 introduces the complete capability: committed cycle state under
.marketing/, the generic (repo-agnostic) marketing-cycle formula in both its runtime and embed locations, and the generated first-class agent.Affected Layers & Files
Cycle state (
.marketing/— committed, following the.designs/pattern)approach.md— the operator-signed runbook: operator identity, channels with homepage allowlist, voice profile, claim-verification map, Standing Assets declarations, explicitPrivacy-Decision: COMMITTED, and the sign-off lineannounced-ledger.md— cross-run record of what has been announced, where, and when; also carries the untold-features backlogcycle-1-audit.md,cycle-1-log.md,cycle-1-story.md,cycle-1-report.md,cycle-1-publish-checklist.md— cycle-1 records (log and story are labeled RECONSTRUCTED: the checks ran live 2026-07-11/12; the files were assembled afterward in the formula's artifact format)cycle-1-linkedin.md,cycle-1-medium.md— the two published drafts (content already public)architecture-diagram.png,social-preview.png,social-preview.svg— declared standing assetsFormula (declarative workflow, 23 steps)
.agentfactory/store/formulas/marketing-cycle.formula.toml— runtime copyinternal/cmd/install_formulas/marketing-cycle.formula.toml— embed copy (ships in theafbinary)Structure: first-run bootstrap that generates the runbook by operator interview and holds for sign-off; four human gates (story approval, draft approval, Tier A merge, publish); five evidence-logged checklist gates that write VERDICT lines to the cycle log; an artifact-manifest gate in cleanup that fails any file tracing to no formula step and no Standing Assets declaration; operator communication via GitHub issues and PR comments (agent mail stays agent-to-agent); data-not-directive guards on untrusted input; homepage-URL validation against the runbook's allowlist.
Agent (first-class, generated by
af formula agent-genfrom formula v2)internal/templates/roles/marketing-cycle.md.tmpl— embedded role template, so the agent identity survives context compression.agentfactory/agents/marketing-cycle/CLAUDE.md— workspace persona.agentfactory/agents/marketing-cycle/.claude/settings.json— hook configuration.agentfactory/agents.json— registrationAdditional Context
git check-ignoresilently skips already-tracked files unless--no-indexis used; the formula's enforcement accounts for this.Acceptance Criteria
.marketing/is accounted for: it traces to a formula artifact or a Standing Assets declaration.