# Archon Session State Machine: How It Manages AI-Assistant Lifecycle Transitions

> Explore the Archon session state machine to understand how it deterministically manages AI-assistant lifecycle transitions like creation, deactivation, and preservation with type safety. Learn more.

- Repository: [Cole Medin/Archon](https://github.com/coleam00/Archon)
- Tags: internals
- Published: 2026-04-10

---

**Archon's session state machine is a deterministic, type-safe model that categorizes transition triggers into `creates`, `deactivates`, or `none` behaviors to govern exactly when AI-assistant sessions are terminated, regenerated, or preserved during conversation flows.**

The session state machine in coleam00/Archon provides the single source of truth for managing AI-assistant conversation lifecycles. Implemented in [`packages/core/src/state/session-transitions.ts`](https://github.com/coleam00/Archon/blob/main/packages/core/src/state/session-transitions.ts), it uses a strictly typed `TransitionTrigger` enum and immutable behavior mappings to ensure every state change is auditable via parent-child session chains stored in the database.

## Core Architecture: Transition Triggers and Behaviors

The state machine centers on the `TransitionTrigger` union type, which enumerates every event capable of forcing a session state change:

```ts
export type TransitionTrigger =
  | 'first-message'          // a brand‑new conversation
  | 'plan-to-execute'       // the user moved from a *plan* step to execution
  | 'isolation-changed'     // the worktree / cwd was switched
  | 'reset-requested'       // user ran /reset
  | 'worktree-removed'      // a worktree was manually deleted
  | 'conversation-closed';  // platform closed the thread

```

Source: [`packages/core/src/state/session-transitions.ts`](https://github.com/coleam00/Archon/blob/main/packages/core/src/state/session-transitions.ts) (lines 10-16)

Each trigger maps to exactly one behavior category in the `TRIGGER_BEHAVIOR` constant:

- **`creates`** – Deactivate the current session **and** immediately create a fresh one (exclusively for `plan-to-execute`)
- **`deactivates`** – Only deactivate the session; the next message lazily initializes a new session (covers `isolation-changed`, `reset-requested`, `worktree-removed`, and `conversation-closed`)
- **`none`** – No session action required (only for `first-message`)

```ts
const TRIGGER_BEHAVIOR = {
  'first-message':      'none',
  'plan-to-execute':   'creates',
  'isolation-changed': 'deactivates',
  'reset-requested':   'deactivates',
  'worktree-removed':  'deactivates',
  'conversation-closed':'deactivates',
} as const;

```

Source: [`packages/core/src/state/session-transitions.ts`](https://github.com/coleam00/Archon/blob/main/packages/core/src/state/session-transitions.ts) (lines 27-34)

## Predicate Helpers for Deterministic Decisions

The system exposes two pure predicate functions to query the state machine without branching logic scattered through the orchestrator:

- **`shouldCreateNewSession(trigger)`** returns `true` only when `TRIGGER_BEHAVIOR[t] === 'creates'`
- **`shouldDeactivateSession(trigger)`** returns `true` for every trigger except `first-message`

```ts
export function shouldCreateNewSession(t: TransitionTrigger) {
  return TRIGGER_BEHAVIOR[t] === 'creates';
}
export function shouldDeactivateSession(t: TransitionTrigger) {
  return TRIGGER_BEHAVIOR[t] !== 'none';
}

```

Source: [`packages/core/src/state/session-transitions.ts`](https://github.com/coleam00/Archon/blob/main/packages/core/src/state/session-transitions.ts) (lines 39-47)

TypeScript's exhaustiveness checking guarantees that any new `TransitionTrigger` added to the union must be handled in `TRIGGER_BEHAVIOR` and these helpers, or compilation fails.

## Plan-to-Execute Transition Detection

A critical workflow in Archon involves detecting when a user moves from planning to execution. When the user runs `execute` immediately after a `plan-feature` command (or GitHub-specific variants), the system identifies this as the `plan-to-execute` trigger—the only trigger in the `creates` category that forces immediate session regeneration.

Source: [`packages/core/src/state/session-transitions.ts`](https://github.com/coleam00/Archon/blob/main/packages/core/src/state/session-transitions.ts) (lines 54-64)

## Orchestrator Integration: From Trigger to Database

The orchestrator in [`packages/core/src/orchestrator/orchestrator-agent.ts`](https://github.com/coleam00/Archon/blob/main/packages/core/src/orchestrator/orchestrator-agent.ts) consumes the state machine to manage session lifecycle without embedding business logic in database queries.

### Handling the First Message

When a conversation contains no active session, the orchestrator uses the `first-message` trigger to initialize state:

```ts
if (!session) {
  session = await sessionDb.transitionSession(conv.id, 'first-message', {
    ai_assistant_type: conv.ai_assistant_type,
  });
}

```

Source: [`packages/core/src/orchestrator/orchestrator-agent.ts`](https://github.com/coleam00/Archon/blob/main/packages/core/src/orchestrator/orchestrator-agent.ts) (lines 45-52)

### Processing Slash Commands and State Changes

For subsequent interactions, the orchestrator maps slash commands to triggers via `getTriggerForCommand` (defined in [`session-transitions.ts`](https://github.com/coleam00/Archon/blob/main/session-transitions.ts) lines 71-89). When a command like `/reset` is parsed, the orchestrator evaluates the trigger:

```ts
const trigger = getTriggerForCommand('reset'); // → 'reset-requested'

```

If `shouldDeactivateSession(trigger)` returns `true`, the orchestrator invokes `sessionDb.transitionSession`, which performs an atomic database operation:

1. **Deactivates** the current session (`active = false`, sets `ended_at` and `ended_reason`)
2. **Creates** a new session row linked via `parent_session_id`
3. **Records** the trigger in `transition_reason` for audit trails

```ts
// inside transitionSession()
if (current) {
  await query(
    `UPDATE remote_agent_sessions SET active = false, ended_at = ${dialect.now()}, ended_reason = $2 WHERE id = $1`,
    [current.id, reason]
  );
}
// create new linked session …

```

Sources: [`packages/core/src/db/sessions.ts`](https://github.com/coleam00/Archon/blob/main/packages/core/src/db/sessions.ts) (lines 22-33 and 71-78)

## Practical Implementation Examples

### Detecting Transitions from Slash Commands

```ts
import { getTriggerForCommand, shouldDeactivateSession } from '@archon/core/src/state/session-transitions';

const command = 'reset';
const trigger = getTriggerForCommand(command); // 'reset-requested'

if (trigger && shouldDeactivateSession(trigger)) {
  await sessionDb.transitionSession(conversation.id, trigger, {
    ai_assistant_type: conversation.ai_assistant_type,
  });
}

```

### Forcing New Session Creation After Plan-to-Execute

```ts
import { shouldCreateNewSession } from '@archon/core/src/state/session-transitions';

const trigger = 'plan-to-execute';
if (shouldCreateNewSession(trigger)) {
  const newSess = await sessionDb.transitionSession(conv.id, trigger, {
    ai_assistant_type: conv.ai_assistant_type,
  });
  // `newSess.id` is now the fresh session used for the execution phase
}

```

### Walking the Session Audit Chain

```ts
import { getSessionChain } from '@archon/core/src/db/sessions';

const chain = await getSessionChain(session.id);
chain.forEach(s => console.log(`Session ${s.id} – reason: ${s.transition_reason}`));

```

## Summary

- **Type-Safe Triggers**: The `TransitionTrigger` enum and `TRIGGER_BEHAVIOR` mapping provide compile-time guarantees that all state transitions are handled.
- **Three Behavioral Categories**: Triggers classify as `creates` (immediate regeneration), `deactivates` (lazy next-session creation), or `none` (no action).
- **Database Audit Trail**: Every transition updates the `remote_agent_sessions` table with `active`, `ended_reason`, `parent_session_id`, and `transition_reason` fields.
- **Orchestrator Abstraction**: The orchestrator delegates state decisions to pure functions in [`session-transitions.ts`](https://github.com/coleam00/Archon/blob/main/session-transitions.ts) while [`sessions.ts`](https://github.com/coleam00/Archon/blob/main/sessions.ts) handles atomic DB operations.
- **Plan-to-Execute Special Case**: Only the `plan-to-execute` trigger uses the `creates` behavior, ensuring execution phases receive fresh session contexts.

## Frequently Asked Questions

### How does Archon determine when to create a new AI-assistant session versus just deactivating the current one?

Archon uses the `shouldCreateNewSession()` predicate to check if a trigger maps to the `creates` behavior category. Currently, only the `plan-to-execute` trigger returns `true`, forcing immediate creation of a new session. All other triggers either use `deactivates` (which waits for the next message to lazily create a session) or `none` (for the first message in a conversation).

### What happens to session data when a user runs the `/reset` command?

The orchestrator maps `/reset` to the `reset-requested` trigger via `getTriggerForCommand()`. Since this trigger classifies as `deactivates`, the `transitionSession()` function in [`packages/core/src/db/sessions.ts`](https://github.com/coleam00/Archon/blob/main/packages/core/src/db/sessions.ts) sets `active = false` and records `ended_reason` on the current row, then creates a new session with a `parent_session_id` link to the old one. The historical session remains in the database for audit purposes but is no longer active.

### Where is the session state machine logic located in the Archon codebase?

The core state machine definitions reside in [`packages/core/src/state/session-transitions.ts`](https://github.com/coleam00/Archon/blob/main/packages/core/src/state/session-transitions.ts), which exports the `TransitionTrigger` type, `TRIGGER_BEHAVIOR` constants, and predicate helpers. The database implementation lives in [`packages/core/src/db/sessions.ts`](https://github.com/coleam00/Archon/blob/main/packages/core/src/db/sessions.ts), while the orchestrator that consumes these utilities is in [`packages/core/src/orchestrator/orchestrator-agent.ts`](https://github.com/coleam00/Archon/blob/main/packages/core/src/orchestrator/orchestrator-agent.ts).

### Why does the `plan-to-execute` trigger behave differently from other triggers?

The `plan-to-execute` trigger represents a workflow boundary where the AI assistant transitions from planning mode to execution mode. According to the source code in [`session-transitions.ts`](https://github.com/coleam00/Archon/blob/main/session-transitions.ts), this is the only trigger classified under `creates` because execution phases require a completely fresh context without carrying over planning state, whereas other triggers like `isolation-changed` or `reset-requested` simply deactivate the session to be lazily recreated on the next user message.