---
title: "Spike mode: time-boxed, disposable work | CommitCycle"
description: "Time-boxed, disposable exploration — promote what earned it, discard the rest and prove nothing was left behind."
url: https://commitcycle.com/docs/concepts/spike-mode/
language: en
---

# Spike mode

> Time-boxed, disposable exploration — promote what earned it, discard the rest and prove nothing was left behind.

A **spike** is a mode on a task, not a state: `mode: spike` on the task, work on the task’s own branch, and a **time box** — 7 days, warned about from day 5 — instead of an open-ended licence to explore. `cycle start` cuts that branch as `task/<id>-<slug>` for a spike too; a `spike/` branch comes only from a start that names no branch, from the console or the connector, where the gate derives it. The five states are unchanged; nothing about a spike adds a sixth.

Two rules make it worth using. The database schema stays closed for the whole spike **whatever the grant says** — sandbox objects take a `spike_<task>_` prefix so they can be dropped together. And exploration is disposable by default: `cycle discard` costs one command, `cycle promote` costs one command _and a confirmation_. That gap is deliberate. The usual end of an experiment is that it goes away, so the cheaper path is the one that throws it out.

## Discarding, and the proof

```plaintext
cycle discard CC-231
```

It refuses unless the checkout stands on that spike’s own branch, since it resets whatever is checked out (CC-1250). Then it runs the project’s own cleanup command, resets the branch to its base, removes untracked files — and reports three checks rather than claiming success:

| check           | what passes                                            |
| --------------- | ------------------------------------------------------ |
| repository diff | nothing differs from the base the branch forked at     |
| identifiers     | no file still names `spike_<task>`                     |
| `spike_verify`  | the project’s own verification command printed nothing |

**A check that could not run says “not declared”, never “clean.”** That is the whole difference between a proof and a reassurance, and it is why the command prints all three lines every time.

## What CC will not do

CC demands and verifies; it does not execute things of its own. Dropping a sandbox table means running DDL against _some_ database, and only the project knows which — so the reversion outside the repository runs through commands the project declares in `.zones/zones.yml`:

```yaml
config:
  spike_env: "postgres://localhost/app_dev"   # where exploration runs — never shared data
  spike_cleanup: "npm run db:drop-spike --"   # your command, handed the spike_<task>_ prefix
  spike_verify: "npm run db:list-spike --"    # your command; empty output is the pass
```

Nothing is guessed. With no `spike_cleanup` configured, no command runs at all, and a discard that finds `spike_` identifiers with nowhere to clean them is **refused before anything is undone** — with the alternative of `--manual "..."`, which records the cleanup as a manual step in the trail instead of pretending it happened.

Feature flags living in third-party services are the same: the inventory lists them, and discard reports them as a manual step. CC does not promise to revert what it cannot see.

## The time box

`cycle status` names the deadline from day one, warns from day 5, and from day 7 offers both ways out. **It never deletes anything, at any age.** A product that tidies up after you is a product that one day removes work somebody wanted — and after that nobody leaves a spike running long enough to learn anything from it. The clock proposes; a person answers; doing neither is also an answer.

CC’s own development ran the discipline by hand first: Phase 0’s `spikes/` directory was deleted at the phase gate, its case tables promoted into evals and its implementations discarded on purpose — one of them carried a bug a later task caught, and promoting it would have shipped the bug.

_Evals E17 (zero residue), E18 (promotion keeps what was chosen, and costs the extra confirmation) and E20 (expiry proposes, never deletes) assert this in CI. E16 — the refusal proposing `spike_` by name — is still pending._
