Docs/Config

Advanced

When hooks run, how state flows between steps, and what happens on failure. Read Write a lump first.

On this page
  1. When hooks run
  2. contextRunState
  3. Discovery hooks
  4. Dynamic steps
  5. Custom commands
  6. promptFn
  7. Failure modes worth knowing

Every *Fn is an inline function in config.js / config.ts, or a string path to a module whose default export is that function. Paths are relative to the lump folder.

When hooks run

After Lumpcode has a todo list and a branch workspace:

  1. postSetupWorkspaceFn / postSetupWorkspaceCommand once (for example npm ci).
  2. For each context: lump setupFn, then each command module setup.
  3. Walk steps / prompt. Each leaf: resolve prompt → run command → postCommandExecFn (may return more steps).
  4. Command module teardown, then lump teardownFn.
  5. Marker git add + commit. Next context, or push.
  6. postTeardownWorkspaceFn / Command, then generated workspace teardown.

Teardown still runs if the step walk fails. A failed walk skips git for that context, the remaining contexts, and push. Teardown errors are logged and do not become the run failure.

lump-plan does not run post-setup / post-teardown commands. --prompts / --plan may execute promptFn and dynamic steps so the preview is honest; they still do not spawn the agent or mutate git.

Shared loads and runs on this checkout (no pre-flight). Dedicated locked-preflights the clone to the scan branch before load (allowlist), then pre-flights baseBranch for the run. commandFn returning nothing still runs postCommandExecFn. Signatures: types.

contextRunState

One mutable object per context run. The engine never clones it. Typical uses:

Stage Convention
setupFn Seed { contextRunState: { … } }.
Command setup Namespaced at <commandName>Setup (session ids).
postCommandExecFn Parse stdout, set flags, or return follow-on steps.
Dynamic steps Read flags to include or skip the next prompt.
config.ts
setupFn() {
  return { contextRunState: { attempt: 0 } }
}

Discovery hooks

Covered with examples on contexts. Short gotchas:

  • getContextListFn variable values must be strings.
  • contextMatchFn merges rows that share contextName.
  • contextOptionsFn runs only with a contextListJson path-template object.

Dynamic steps

A function item receives the same inputs as promptFn (without stepVariables) and returns more steps, a solo item, or [].

config.ts
import { defineConfig } from '@lumpcode/cli-utils'

export default defineConfig({
  command: 'cursor',
  contextListJson: { FILE: 'src/{NAME}.ts' },
  steps: [
    {
      promptTemplate: 'Does @{FILE} need a README section? Reply YES or NO only.',
      postCommandExecFn({ commandResult, contextRunState }) {
        contextRunState.needsDocs = commandResult.toUpperCase().includes('YES')
      },
    },
    ({ contextRunState }) =>
      contextRunState.needsDocs
        ? [{ promptTemplate: 'Add minimal module docs for @{FILE}.' }]
        : [],
  ],
})

postCommandExecFn may itself return the next iteration of a verify loop. Prefer retryUntilGreen from @lumpcode/recipes unless you need a custom shape.

If a command tag other than the lump command appears only inside a returned array, set "registerCommands": ["other-agent"] so that module’s setup still runs.

config.ts
registerCommands: ['reviewer'],
steps: [
  { promptTemplate: 'Edit @{FILE}.' },
  () => [{ command: 'reviewer', promptTemplate: 'Review @{FILE}.' }],
]

Custom commands

See agents for presets and a minimal module. Order of setup: lump setupFn, then each command setup. Teardown is the reverse. Worktree strategy releases the execution-path lock after setup returns; git mutations stay under the git-common-dir lock.

promptFn

Use when the prompt must include previous stdout or branch on contextRunState. Mutually exclusive with promptTemplate on that step. promptFn is not scanned for {VAR}; concatenate context.variables yourself if you need them.

config.ts
{
  promptFn({ context, contextRunState }) {
    return `Last output:\n${contextRunState.lastOutput}\n\nEdit ${context.variables.FILE}.`
  },
}

Failure modes worth knowing

What happened Result
Step walk failed or aborted No git for that context, no further contexts, no push. reason: stepWalkFailed.
gitAddCommitFn failed / empty string / throw Hard fail, remaining contexts skipped.
Only workspace teardown failed workspaceTeardownFailed unless a walk/commit failure was already recorded.
git push failed Logged; not a hard fail.

Ctrl+C on a manual run: first signal aborts, second force-exits. A worker mid-run refuses a graceful stop until you pass --force or wait for idle.

Edit this page