Orchestrata Ultimate / Specs / 023-goal-system

023-goal-system: Goal-Driven Session System

A persistent, measurable goal system that drives agent behavior across sessions, context compactions, and conversation restarts. The agent commits to a goal, decomposes it into tasks, continuously evaluates progress against boolean exit criteria, and does not stop until the goal is achieved or the agent is blocked. When either condition is reached, an audio alarm alerts the user.

At a glance

Item Value
Spec directory specs/023-goal-system/
Status line in the spec Draft
Requirement IDs defined 155
With a @traces citation in src/ 17 (11.0%)
With a @traces citation in tests/ 0 (0.0%)
Tracked files 3
RTM page 023-goal-system

Reading this spec

The Goal-Driven Session System is a persistent, measurable goal mechanism that drives agent behavior across sessions, context compactions and conversation restarts. The agent commits to a goal, breaks it into tasks, evaluates progress against boolean exit criteria and does not stop until the goal is achieved or the agent is blocked; an audio alarm then alerts the user. The spec names three problems it solves: goal amnesia after compaction or restart, premature stopping, and silent completion.

The scope is seven user stories: setting a session goal, continuous progress evaluation, persistence across compaction and the Stop hook guard (priority 0), and the audio alarm, reflective re-planning and goal lifecycle commands (priority 1). The functional requirements add exit criterion validation and blocker detection and notification. Requirement IDs use the REQ-023- prefix.

The central design decision is a BDI (Belief-Desire-Intention) architecture mapped onto the session infrastructure of spec 006. Beliefs are the context.json state, desires are the goal statement with exit criteria, and intentions are the active goal with committed tasks. The goal persists in context.json under state.goal. Session hooks inject it at startup, and the Stop hook checks it before the agent may stop.

In the code, the largest tracers are orchestrata_ultimate/session/controller/_goals and orchestrata_ultimate/session/audio_alarm, with orchestrata_ultimate/session/hooks/session_auto_start_hook and orchestrata_ultimate/session/exceptions. The per-requirement view is on the RTM page.

The spec's status line reads Draft. It tracks 3 files and defines 155 requirement IDs. The full text follows below.

Measured coverage is 17 of 155 requirements cited by at least one @traces in src/ (11.0%), spread over 4 modules; the module citing the most of them is orchestrata_ultimate/session/controller/_goals (10 requirements). In tests/, 0 requirements are cited by a test-side @traces.

Coverage gaps: 138 requirements have no citing symbol. The largest untraced groups are REQ-023-* (138). Untraced means no @traces names the ID; the behaviour may still exist in code that was never annotated. Test-side citations are thinner than code-side ones (0 against 17).

Requirements

Checkbox is the state recorded in the requirements checklist; Traced by is the count of src/ symbols whose @traces names the ID.

ID Done Requirement Traced by
REQ-023-007 yes After every CI run, test execution, or code change, the agent evaluates all exit criteria — GoalMixin.goal_evaluate runs every verify_command; auto-triggered by the US-005 Stop gate and exposed as session goal evaluate. Tests: tests/session/test_goal_evaluate.py. 2
REQ-023-008 yes A criterion transitioning pending -> met is logged and announced — goal_evaluate logs a progress entry and prints the transition. Tests: tests/session/test_goal_evaluate.py. 1
REQ-023-009 yes A criterion regressing met -> failed is logged and announced — goal_evaluate re-runs verifiers on met criteria and logs regressions. Tests: tests/session/test_goal_evaluate.py. 1
REQ-023-010 yes All criteria met => goal transitions to achieved (achieved_at recorded). Tests: tests/session/test_goal_evaluate.py. 1
REQ-023-011 yes Evaluation is automatic — wired into SessionController.end()'s Stop gate; the user does not trigger it. Tests: tests/session/test_goal_stop_gate.py. 1
REQ-023-012 yes Each evaluation is logged as a progress entry with timestamp — GoalProgress entry per evaluation. Tests: tests/session/test_goal_evaluate.py. 1
REQ-023-013 yes The goal persists in context.json under state.goal — ContextFileManager store, untouched by compaction (pre-existing). none
REQ-023-014 yes A new session injects the goal into the conversation — session_auto_start_hook._format_goal_injection. Tests: tests/session/test_session_auto_start_hook.py. 1
REQ-023-015 yes The first hook output includes the goal statement and criteria status. Tests: tests/session/test_session_auto_start_hook.py. 1
REQ-023-016 yes The goal is always in context.json, never conversation memory alone (pre-existing). none
REQ-023-017 yes All criteria met => success alarm (ascending tones) — AudioAlarm.play_success, triggered by goal_evaluate and /goal achieved. Tests: tests/session/test_audio_alarm.py. 1
REQ-023-018 yes Blocked => attention alarm (low tones) — AudioAlarm.play_attention, triggered by /goal block and the Stop gate. Tests: tests/session/test_audio_alarm.py. 1
REQ-023-019 yes Backend chain ffplay -> paplay -> aplay -> mpv -> terminal bell — audio_alarm.select_backend. Tests: tests/session/test_audio_alarm.py. 1
REQ-023-020 yes Alarm repeats every 30 seconds until the user sends a message — AudioAlarm.start_repeat/stop (daemon thread). Tests: tests/session/test_audio_alarm.py. 1
REQ-023-021 yes Alarm is non-blocking — detached subprocesses + daemon thread. Tests: tests/session/test_audio_alarm.py. 1
REQ-023-022 yes On every Stop event the gate reads state.goal from context.json — _enforce_goal_stop_gate runs in SessionController.end(). Tests: tests/session/test_goal_stop_gate.py. 2
REQ-023-023 yes Active + incomplete + unblocked => inject "Goal not achieved. Remaining: [...]" and refuse the stop (GoalNotAchievedError). Tests: tests/session/test_goal_stop_gate.py. 2
REQ-023-024 yes Active + blocked => inject the blocker reason and trigger the attention alarm. Tests: tests/session/test_goal_stop_gate.py. 1
REQ-023-025 yes No active goal => the gate does nothing. Tests: tests/session/test_goal_stop_gate.py. 1
REQ-023-026 yes The agent reads the injected message and resumes — the CLI surfaces the injected text in the error (behavioral; no separate test). none
REQ-023-027 no Task failure logs the failure and evaluates alternative approaches. none
REQ-023-028 no Criterion regression creates a new investigation task. none
REQ-023-029 no Re-planning never discards completed tasks. none
REQ-023-030 no 3 failed attempts on the same task => goal blocked + alarm. none
REQ-023-031 no Re-planning logged as a progress entry. none
REQ-023-032 yes /goal set <statement> defines the goal, replacing any existing active goal (pre-existing). Tests: tests/session/test_session_cli.py. none
REQ-023-033 yes /goal status shows statement, criteria, tasks, progress, blockers (pre-existing). Tests: tests/session/test_session_cli.py. none
REQ-023-034 yes /goal achieved marks achieved (override) + success alarm. Tests: tests/session/test_session_cli.py. none
REQ-023-035 yes /goal abandon [reason] abandons and logs the reason (pre-existing). Tests: tests/session/test_session_cli.py. none
REQ-023-036 yes /goal block <reason> marks blocked + attention alarm. Tests: tests/session/test_session_cli.py. none
REQ-023-037 yes /goal unblock clears the blocked status and resumes. Tests: tests/session/test_session_cli.py. none
REQ-023-038 yes All commands update context.json atomically — every command writes through ContextFileManager (pre-existing). none
REQ-023-001 - The goal system SHALL NOT execute destructive actions autonomously — it SHALL evaluate criteria and propose tasks, and execution SHALL still require tool approval per the existing permission model (Article III — Harm Prevention). none
REQ-023-002 - Given a new session with no active goal, when the session starts, then the agent SHALL prompt the user to define a goal before beginning work none
REQ-023-003 - Given the command /goal set, when the user provides a statement, then the agent SHALL decompose it into exit criteria and tasks interactively none
REQ-023-004 - Given exit criteria, when each is defined, then it SHALL be stored as a boolean condition with status pending none
REQ-023-005 - Given a goal is set, when context.json is read, then state.goal SHALL contain the full goal structure none
REQ-023-006 - Given a goal is set, when a new session starts (including after compaction), then the goal SHALL be displayed with current criteria status none
REQ-023-039 - The system SHALL play the sound pattern defined for each event: goal achieved — 3 ascending tones at 600, 800 and 1000 Hz for 0.2s, 0.2s and 0.3s; agent blocked — 2 low tones at 300 Hz repeated for 0.3s each; criterion met — a single 800 Hz tone for 0.2s; criterion regressed — a descending tone at 500 Hz then 300 Hz for 0.2s and 0.3s. none
REQ-023-040 - On achievement the alarm SHALL play once and then every 30 seconds until the user sends a message; on blocked it SHALL play once and then every 60 seconds until the user sends a message. none
REQ-023-041 - The alarm repeat SHALL be a background process that checks the flag file /tmp/orchestrata-alarm-active, and a user message received via the UserPromptSubmit hook SHALL remove the flag file and stop the alarm. none
REQ-023-042 - The system SHALL persist all goal state in context.json including statement, criteria, tasks, progress, and blockers. none
REQ-023-043 - The goal SHALL survive session restarts, context compaction, and conversation truncation. none
REQ-023-044 - The SessionStart hook SHALL read the goal from context.json and inject it into the conversation. none
REQ-023-045 - If an active goal exists, the hook SHALL display the goal statement and all criteria with current status indicators ([x] for met, [ ] for pending). none
REQ-023-046 - After every CI run, test execution, or code modification, the system SHALL automatically evaluate all goal criteria. The evaluation SHALL NOT require user intervention and SHALL be triggered by session events. none
REQ-023-047 - Each exit criterion SHALL be validated by executing its verify_command and matching against its verify_pattern. none
REQ-023-048 - The system SHALL transition criterion status from pending to met when the pattern matches successfully. none
REQ-023-049 - The Stop hook SHALL prevent the agent from stopping when an active goal exists with unachieved criteria. none
REQ-023-050 - The hook SHALL inject a continue message and signal continuation instead of allowing the stop. none
REQ-023-051 - When all exit criteria are met, the system SHALL play a success audio alarm. none
REQ-023-052 - When the goal becomes blocked, the system SHALL play an attention audio alarm. none
REQ-023-053 - The alarm SHALL persist until the user sends a message. none
REQ-023-054 - The system SHALL support /goal commands for set, status, achieved, abandon, block, and unblock operations. none
REQ-023-055 - All commands SHALL update context.json atomically and SHALL provide user feedback. none
REQ-023-056 - When a task fails or a criterion regresses, the system SHALL evaluate alternative approaches. none
REQ-023-057 - After 3 consecutive failures on the same task, the system SHALL mark the goal as blocked with a reason. none
REQ-023-058 - The system SHALL detect blockers that prevent goal progress. Blockers MAY be auto-detected (network failures, permission errors) or user-defined via /goal block. none
REQ-023-059 - When blocked, the system SHALL trigger the attention alarm. none
REQ-023-060 - The system SHALL enforce goal state transitions according to the defined state machine: none → active → (achieved|blocked|abandoned). Invalid transitions SHALL be rejected. none
REQ-023-061 - Every goal state change SHALL be logged as a progress entry with timestamp, action, notes, and criteria changes. none
REQ-023-062 - Progress SHALL be stored in context.json and MAY be persisted to Neo4j. none
REQ-023-063 - When a previously met criterion regresses to failed status, the system SHALL log the regression, announce it to the user, and trigger re-planning to address the regression. none
REQ-023-064 - The system SHALL detect the first available audio backend at startup using the fallback chain: ffplay, paplay, aplay, mpv, terminal bell. none
REQ-023-065 - The detected backend SHALL be cached for subsequent use. none
REQ-023-066 - The goal field in context.json SHALL maintain referential integrity: task criteria references SHALL match existing criterion IDs. none
REQ-023-067 - Invalid references SHALL be rejected during goal creation. none
REQ-023-068 - An active goal SHALL be visible across all sessions within the same project. none
REQ-023-069 - New Claude Code sessions SHALL receive the goal via session hooks, not via conversation memory. none
REQ-023-070 - Audio alarms SHALL NOT block agent output or tool execution. none
REQ-023-071 - Alarms SHALL run as background processes with a flag file to coordinate state. none
REQ-023-072 - When a goal is abandoned, the system SHALL log the abandonment reason, timestamp, and SHALL NOT auto-resume. none
REQ-023-073 - Abandoned goals SHALL be displayable via /goal status. none
REQ-023-074 - ERR-001 — When a goal is set with a blank statement, the system SHALL reject it with the error "Goal statement cannot be blank" and SHALL maintain no active goal. none
REQ-023-075 - ERR-002 — When a criterion has no verify_command or verify_pattern, the system SHALL allow its creation with a warning, and that criterion SHALL be transitionable only via /goal achieved. none
REQ-023-076 - ERR-003 — When a goal state transition targets an invalid state, the system SHALL reject the transition, log the error, and maintain the current state. none
REQ-023-077 - ERR-004 — When no audio backend is available, the system SHALL log a warning, disable audio alarms, and continue with the terminal bell only. none
REQ-023-078 - ERR-005 — When the goal field in context.json is corrupted JSON, the system SHALL fall back to no active goal and log the error to the system logs. none
REQ-023-079 - ERR-006 — When the Stop hook cannot read the goal from context.json, it SHALL allow the stop (existing behavior), log the error, and flag it for manual review. none
REQ-023-080 - ERR-007 — When all criteria remain pending after 100 task completions, the system SHALL log the warning "Goal may be mis-specified" and SHALL continue evaluation. none
REQ-023-081 - ERR-008 — On a goal ID collision during goal creation, the system SHALL generate a new unique ID with a timestamp suffix and log a warning. none
REQ-023-082 - ERR-009 — When a task references a non-existent criterion ID, the system SHALL reject the task creation and return an error carrying the valid criterion IDs. none
REQ-023-083 - ERR-010 — When goal evaluation times out after 30 seconds, the system SHALL log the timeout error and continue to the next evaluation cycle. none
REQ-023-084 - ERR-011 — When an alarm process cannot be spawned, the system SHALL log the error to the system logs and continue without audio. none
REQ-023-085 - ERR-012 — When the flag file /tmp/orchestrata-alarm-active cannot be written, the system SHALL disable the alarm repeat and play the alarm once only. none
REQ-023-086 - ERR-013 — On a user prompt during an alarm repeat, the system SHALL attempt to kill the alarm process and SHALL log the success or failure. none
REQ-023-087 - ERR-014 — When Neo4j persistence fails for goal state, the system SHALL continue with context.json only and log the error to the system logs. none
REQ-023-088 - ERR-015 — When re-planning generates no new tasks after 3 failures, the system SHALL mark the goal as blocked with the reason "No alternative approaches found". none
REQ-023-089 - ERR-016 — On goal achievement with conflicting criterion statuses, the system SHALL log the error and require manual resolution via the /goal achieved override. none
REQ-023-090 - ERR-017 — On session start with corrupted goal progress entries, the system SHALL filter the invalid entries, continue with the valid entries, and log a warning. none
REQ-023-091 - ERR-018 — When the alarm backend probe fails for all backends, the system SHALL fall back to the terminal bell (\a) and log all backend failures. none
REQ-023-092 - ERR-019 — When a goal criterion verify_command execution fails, the system SHALL log the failure, maintain the pending status, and continue with the next criterion. none
REQ-023-093 - ERR-020 — On multiple concurrent goal updates (race condition), last write SHALL win and the system SHALL log a warning about the concurrent modification. none
REQ-023-094 - SessionController SHALL expose the goal API with the parameters, return values, side effects and exceptions defined in this section: goal_set(statement: str, criteria: list[dict]) -> Goal, goal_evaluate() -> dict[str, str], goal_status() -> dict, goal_achieve(reason: str) -> bool, goal_abandon(reason: str) -> bool, goal_block(reason: str) -> bool, and goal_unblock() -> bool. none
REQ-023-095 - AudioAlarm SHALL expose play_success_alarm() -> bool, play_blocked_alarm() -> bool and cancel_alarms() -> bool, and the hook layer SHALL expose session_start_goal_injection() -> str and stop_hook_goal_check() -> bool, with the return semantics defined in this section. none
REQ-023-101 - Goal evaluation SHALL complete within 30 seconds none
REQ-023-102 - Audio alarm playback SHALL complete within 5 seconds none
REQ-023-103 - context.json reads/writes SHALL complete within 1 second none
REQ-023-104 - Session hook execution SHALL complete within 2 seconds none
REQ-023-105 - Goal system SHALL maintain functionality if audio alarms fail none
REQ-023-106 - Goal persistence SHALL work even if Neo4j is unavailable none
REQ-023-107 - Session hooks SHALL gracefully degrade if context.json is temporarily unavailable none
REQ-023-108 - Goal statements SHALL NOT execute arbitrary code none
REQ-023-109 - verify_command values SHALL be validated against a whitelist of safe commands none
REQ-023-110 - Goal status updates SHALL be logged for audit none
REQ-023-111 - User SHALL be able to abandon goals at any time (user autonomy) none
REQ-023-112 - System SHALL support up to 50 active criteria per goal none
REQ-023-113 - System SHALL support up to 1000 progress entries per goal none
REQ-023-114 - System SHALL support concurrent goal operations from multiple session instances none
REQ-023-115 - Goal model SHALL be defined using Pydantic for validation none
REQ-023-116 - Hook architecture SHALL be modular for easy testing none
REQ-023-117 - Error conditions SHALL be logged with context for debugging none
REQ-023-118 - Goal state SHALL be consistent across session restarts none
REQ-023-119 - Audio alarms SHALL have fallback chain to ensure user notification none
REQ-023-120 - Goal evaluation SHALL be idempotent (multiple evaluations yield same result) none
REQ-023-121 - Goal status SHALL be human-readable at a glance none
REQ-023-122 - Audio alarms SHALL be distinguishable by sound pattern none
REQ-023-123 - Goal commands SHALL provide immediate feedback none
REQ-023-124 - Goal statements SHALL be validated for maximum length (512 characters) none
REQ-023-125 - Reason strings for abandon/block SHALL be sanitized to prevent injection none
REQ-023-126 - User SHALL be able to inspect and override any automated goal operations none
REQ-023-127 - All goal state changes SHALL be logged with timestamp, user, and reason none
REQ-023-128 - Goal progress SHALL be stored in Neo4j for complete audit trail none
REQ-023-129 - Authentication status SHALL be included in all goal-related logs none
REQ-023-130 - Failed verification commands SHALL be logged with full error context none
REQ-023-131 - Any user SHALL be able to view goal status none
REQ-023-132 - Any user SHALL be able to abandon or block goals none
REQ-023-133 - Goal modification SHALL require an active session (no background changes without user action) none
REQ-023-134 - Critical operations (abandon, achieve) SHALL be confirmed before execution none
REQ-023-135 - Goal data SHALL NOT contain sensitive information (passwords, tokens) none
REQ-023-136 - context.json file SHALL have restricted permissions (owner read/write only) none
REQ-023-137 - Audio alarms SHALL NOT expose system information in their execution none
REQ-023-096 - The goal schema in context.json SHALL be versioned for backward compatibility none
REQ-023-097 - local-ci.sh results SHALL be parsed for criterion evaluation: test pass/fail counts extracted from JUnit XML, coverage reports parsed for threshold verification, and lint output checked for clean status. none
REQ-023-098 - Goal state persisted to Neo4j SHALL use Goal nodes with a CONTAINS relationship to criteria and a HAS_TASK relationship to task nodes, and SHALL support cross-session goal-history queries and goal-achievement-rate analytics. none
REQ-023-099 - When no goal exists or the goal is not active, the SessionStart hook SHALL output No active goal. Use /goal set <statement> to define one. none
REQ-023-100 - When the Stop hook evaluates all criteria and finds them all met, it SHALL mark the goal achieved, play the success alarm and allow the stop; when the goal is blocked, it SHALL play the blocked alarm and allow the stop. none
REQ-023-138 - Primary Framework: pytest for Python test implementation none
REQ-023-139 - Test Type: Behavior-Driven Development (BDD) approach emphasizing goal-oriented testing none
REQ-023-140 - Test Organization: Tests grouped by functional requirement (FR-<num>) and user story (US-<num>) none
REQ-023-141 - Mocking Policy: No mocking of core goal system components; real implementations required for authentic testing none
REQ-023-142 - Assertion Style: Use explicit assertions with descriptive error messages none
REQ-023-143 - Each functional requirement MUST have corresponding unit tests: none
REQ-023-144 - Each user story MUST have end-to-end tests simulating real usage: none
REQ-023-145 - Line-coverage minimums SHALL be met: goal system modules 95%, session controller 90%, audio alarm system 85% (hardware-dependent), hook architecture 90%, overall system 90%. none
REQ-023-146 - Coverage measurement SHALL exclude audio backend probe failures, actual audio playback, and Neo4j unavailability. none
REQ-023-147 - The pre-commit hook SHALL run the goal system unit tests, enforce the 90% coverage threshold, and validate JSON schema conformity. none
REQ-023-148 - CI SHALL run python -m pytest tests/test_goal_system/ -v --cov=src/goal_system --cov-report=term-missing. none
REQ-023-149 - Test runs SHALL generate JUnit XML for CI integration, HTML coverage reports for developer review, and test execution timing reports for performance monitoring. none
REQ-023-150 - Each error condition MUST have tests verifying proper handling: none
REQ-023-151 - The goal system SHALL log all major operations with appropriate log levels, include correlation IDs for request tracing, log performance metrics for critical operations, and log errors with full context for debugging. none
REQ-023-152 - The goal system SHALL expose performance metrics: operation duration histograms, request/error rate counters, resource utilization gauges, and business metrics relevant to the domain. none
REQ-023-153 - The goal system SHALL support distributed tracing: trace propagation across component boundaries, span attributes for domain-specific context, and trace sampling based on operational needs. none
REQ-023-154 - The goal system SHALL raise critical alerts on error rate spikes, performance degradation, resource exhaustion, and business metric anomalies. none
REQ-023-155 - The goal system SHALL provide an operational dashboard covering real-time system health, performance trends, error analysis, and resource monitoring. none

Code that traces this spec

Module Symbols Requirements
orchestrata_ultimate/session/audio_alarm 1 5
orchestrata_ultimate/session/controller/_goals 3 10
orchestrata_ultimate/session/exceptions 1 2
orchestrata_ultimate/session/hooks/session_auto_start_hook 1 2

Checklists

checklists/requirements.md

The requirement list above comes from this file; 27 of 32 checkbox items are ticked.

Other tracked files

Full spec text

Verbatim from specs/023-goal-system/spec.md; headings are pushed down two levels.

SPEC-023: Goal-Driven Session System

Metadata


Overview

What

A persistent, measurable goal system that drives agent behavior across sessions, context compactions, and conversation restarts. The agent commits to a goal, decomposes it into tasks, continuously evaluates progress against boolean exit criteria, and does not stop until the goal is achieved or the agent is blocked. When either condition is reached, an audio alarm alerts the user.

Why

Sessions without goals drift. Today, the session system (Spec 006) tracks what happened but not what was supposed to happen. The session purpose is a timestamp string, not a contract. When context compaction occurs, the agent loses track of intent. When the user steps away, the agent stops and waits instead of continuing toward the objective. The result: the user must repeatedly re-state intent, re-orient the agent, and manually track progress.

This spec solves three problems:

  1. Goal amnesia — the agent forgets what it's working toward after compaction or restart
  2. Premature stopping — the agent stops when it could continue autonomously
  3. Silent completion — the agent finishes or gets blocked with no way to notify the user
How

BDI (Belief-Desire-Intention) architecture mapped onto the existing Orchestrata session infrastructure:

The goal persists in context.json under state.goal — the same file that survives everything. Session hooks inject it at startup. The Stop hook checks it before allowing the agent to stop. An audio alarm bridges the attention gap when the user is away.


Visual Architecture

Class Diagram

Diagram source shown as text: Mermaid could not parse it (Error: Parse error on line 239:).

classDiagram
    class MultiAgentEditResult {
        +file_path: str
        +old_string: str
        +new_string: str
        +agent_results: dict[Any]
        +aggregated_result: dict[Any]
        +timestamp: datetime = Field()
        +success: bool = True
    }
    class GovernanceError {
    }
    class OrchestrataKernel {
        +__init__(self): None
        +_initialize_agents(self): None
        +get_agents_by_type(self, agent_type): list[Any]
        +get_agent_by_id(self, agent_id): Any
        +async broadcast_to_type(self, agent_type, message): list[Any]
        +async broadcast_to_all(self, message): list[Any]
        +async send_to_agent(self, agent_id, message, sender): Any
    }
    class UltimateOrchestrator {
        +__init__(self): None
        +async execute_multi_agent_edit(self, file_path, old_string, new_string): MultiAgentEditResult
        +_aggregate_agent_results(self, results): dict[Any]
        +async create_project(self, name, path, template): dict[Any]
        +async shutdown(self): None
    }
    class ThreadPoolTaskStatus {
        +PENDING = 'pending'
        +RUNNING = 'running'
        +COMPLETED = 'completed'
        +FAILED = 'failed'
        +CANCELLED = 'cancelled'
        +TIMEOUT = 'timeout'
    }
    class ThreadPoolTask {
        +task_id: str = field()
        +function: Any = None
        +args: tuple = field()
        +kwargs: dict[Any] = field()
        +status: ThreadPoolTaskStatus = .PENDING
        +created_at: datetime = field()
        +started_at: Any = None
        +completed_at: Any = None
        +result: Any = None
        +error: Any = None
        +traceback: Any = None
        +future: Any = None
        +metadata: dict[Any] = field()
    }
    class ThreadPoolManager {
        +__init__(self, max_workers, thread_name_prefix, initializer, initargs)
        +start(self): None
        +stop(self, wait, cancel_futures): None
        +submit(self, fn, *args, **kwargs): str
        +submit_many(self, functions, args_list, kwargs_list): list[str]
        +async submit_async(self, fn, *args, **kwargs): T
        +async submit_many_async(self, functions, args_list, kwargs_list): list[T]
        +async wait_for_task(self, task_id, timeout): Any
        +get_task_status(self, task_id): ThreadPoolTaskStatus
        +get_task_result(self, task_id, wait): Any
        +cancel_task(self, task_id): bool
        +get_stats(self): dict[Any]
        +_wrap_function(self, task_id, fn, *args, **kwargs): T
        +_update_task_from_future(self, task_id, future): None
        +task_context(self, task_id): Any
        +async async_task_context(self, task_id): Any
    }
    class ParallelTestExecutor {
        +__init__(self, thread_pool, max_workers)
        +run_tests_parallel(self, test_paths, pytest_args, timeout_per_test): dict[Any]
        +_run_single_test(self, test_path, pytest_args, timeout): dict[Any]
        +async run_tests_parallel_async(self, test_paths, pytest_args, timeout_per_test): dict[Any]
    }
    class LogLevel {
        +TRACE = 'TRACE'
        +DEBUG = 'DEBUG'
        +INFO = 'INFO'
        +WARNING = 'WARNING'
        +ERROR = 'ERROR'
        +CRITICAL = 'CRITICAL'
    }
    class LogContext {
        +__init__(self, logger, **context)
        +__enter__(self)
        +__exit__(self, exc_type, exc_val, exc_tb)
    }
    class LoggingContext {
        +request_id: Any = None
        +session_id: Any = None
        +trace_id: Any = None
        +span_id: Any = None
        +user_id: Any = None
        +user_email: Any = None
        +user_role: Any = None
        +component: Any = None
        +operation: Any = None
        +extra: dict[Any] = field()
        +created_at: datetime = field()
        ---
        +to_dict(self): dict[Any]
    }
    class ContextManager {
        +get_current_context(): LoggingContext
        +set_current_context(context): None
        +clear_context(): None
        +update_context(**kwargs): LoggingContext
        +create_child_context(**updates): LoggingContext
    }
    class AsyncContext {
        +__init__(self, **context_updates)
        +async __aenter__(self): LoggingContext
        +async __aexit__(self, exc_type, exc_val, exc_tb)
    }
    class Context {
        +__init__(self, **context_updates)
        +__enter__(self): LoggingContext
        +__exit__(self, exc_type, exc_val, exc_tb)
    }
    class AuditAction {
        +LOGIN = 'login'
        +LOGOUT = 'logout'
        +AUTH_FAILURE = 'auth_failure'
        +PERMISSION_CHECK = 'permission_check'
        +PERMISSION_DENIED = 'permission_denied'
        +READ = 'read'
        +CREATE = 'create'
        +UPDATE = 'update'
        +DELETE = 'delete'
        +EXPORT = 'export'
        +IMPORT = 'import'
        +CONFIG_CHANGE = 'config_change'
        +SERVICE_START = 'service_start'
        +SERVICE_STOP = 'service_stop'
        +BACKUP = 'backup'
        +RESTORE = 'restore'
        +USER_CREATE = 'user_create'
        +USER_UPDATE = 'user_update'
        +USER_DELETE = 'user_delete'
        +ROLE_ASSIGN = 'role_assign'
        +ROLE_REVOKE = 'role_revoke'
        +EXTERNAL_CALL = 'external_call'
        +WEBHOOK_RECEIVED = 'webhook_received'
        +API_CALL = 'api_call'
        +WORKFLOW_START = 'workflow_start'
        +WORKFLOW_COMPLETE = 'workflow_complete'
        +ESCALATION = 'escalation'
        +APPROVAL = 'approval'
        +REJECTION = 'rejection'
    }
    class AuditStatus {
        +SUCCESS = 'success'
        +FAILURE = 'failure'
        +PARTIAL = 'partial'
        +PENDING = 'pending'
    }
    class AuditEvent {
        +action: AuditAction
        +timestamp: datetime = field()
        +status: AuditStatus = .SUCCESS
        +actor_id: Any = None
        +actor_type: str = 'user'
        +actor_ip: Any = None
        +actor_user_agent: Any = None
        +resource_type: Any = None
        +resource_id: Any = None
        +resource_path: Any = None
        +operation_id: Any = None
        +operation_name: Any = None
        +operation_duration_ms: Any = None
        +before_state: Any = None
        +after_state: Any = None
        +changes: Any = None
        +request_id: Any = None
        +session_id: Any = None
        +trace_id: Any = None
        +span_id: Any = None
        +component: Any = None
        +severity: str = 'info'
        +details: Any = None
        +error_message: Any = None
        +error_stack: Any = None
        +event_hash: Any = None
        +previous_hash: Any = None
        ---
        +__post_init__(self)
        +calculate_hash(self): str
        +_json_serializer(self, obj)
        +to_dict(self): dict[Any]
        +verify_hash(self): bool
    }
    class AuditLogger {
        +__init__(self, component)
        +log_event(self, event): str
        +log_action(self, action, status, resource_type, resource_id, before_state, after_state, actor_id, actor_type, details, error_message, operation_duration_ms, severity): str
    }
    class AuditOperation {
        +action: Any
        +resource_type: Any = None
        +resource_id: Any = None
        +before_state: Any = None
        +actor_id: Any = None
        +actor_type: str = 'user'
        +component: Any = None
        +details: Any = None
        ---
        +__enter__(self)
        +__exit__(self, exc_type, exc_val, exc_tb)
    }
    class DomainEntity {
        +entity_id: str = Field()
        +is_active: bool = Field()
        ---
        +__init__(self, **data)
        +mark_inactive(self)
        +to_domain_dict(self): dict[Any]
        +get_business_key(self): str
        +__eq__(self, other): bool
        +__hash__(self): int
        +__repr__(self): str
    }
    class Node {
        +node_id: str = Field()
        +node_type: str = Field()
        +name: str = Field()
        +properties: dict[Any] = Field()
        +created_at: datetime = Field()
        +updated_at: datetime = Field()
        +version: int = Field()
        ---
        +to_graph_dict(self): dict[Any]
        +from_graph_dict(cls, data): Node
        +update_properties(self, **kwargs)
        +__str__(self): str
    }
    class Config {
        +arbitrary_types_allowed = True
        +json_encoders = {}
    }
    class TracingLevel {
        +OFF = 0
        +BASIC = 1
        +DETAILED = 2
        +DEBUG = 3
        ---
        +label(self): str
    }
    class TracingConfig {
        +model_config = ConfigDict()
        +enabled: bool = Field()
        +service_name: str = Field()
        +service_version: str = Field()
        +endpoint: Any = Field()
        +sample_rate: float = Field()
        +console_export: bool = Field()
        +tracing_level: TracingLevel = Field()
        ---
        +clamp_sample_rate(cls, v): float
    }
    class MetricsConfig {
        +__init__(self, enabled, port, host, include_system_metrics, system_metrics_interval)
    }
    class RetryStrategy {
        +__init__(self, max_retries, initial_delay, max_delay, backoff_factor, jitter)
        +calculate_delay(self, attempt): float
    }
    class CircuitState {
        +CLOSED = 'closed'
        +OPEN = 'open'
        +HALF_OPEN = 'half_open'
    }
    class CircuitBreaker {
        +__init__(self, failure_threshold, reset_timeout, half_open_max_requests, name)
        +is_closed(self): bool
        +is_open(self): bool
        +is_half_open(self): bool
        +record_success(self): None
        +record_failure(self): None
        +should_allow_request(self): bool
        +async execute(self, operation): T
    }
    class Bulkhead {
        +__init__(self, max_concurrent, max_queue_size, name)
        +async execute(self, operation): T
    }
    Node <|-- DomainEntity

Dependencies

Specification Title Relationship
006 Session Management Extends session lifecycle with goal persistence, hooks for goal injection and stop guard
001 Kernel Uses kernel infrastructure for session management and context persistence
007 Governance Operates under governance framework, ensures human autonomy and transparency in goal operations

Terminology

Term Definition
Goal A single statement of intent with measurable exit criteria, persisted in context.json. Maps to BDI "intention" — a desire the agent has committed to pursuing.
Exit Criterion A boolean condition that must be true for the goal to be achieved. Not subjective — measurable by executing a command or reading a value.
Task A unit of work that moves one or more exit criteria from pending to met. Tasks are ordered by dependency.
Progress Entry A timestamped log of what changed toward the goal. Stored in state.goal.progress.
Blocker A condition that prevents the agent from continuing without user input. Triggers the blocked alarm.
Reflective Re-planning After a task fails or a criterion regresses, the agent re-evaluates the task decomposition and proposes new tasks. From TMS (2025).
Commitment The agent's contract with the goal. A committed goal persists until explicitly achieved, abandoned, or marked impossible. It does not drift, decay, or get forgotten. From BDI theory.

Governance

This spec operates under the existing Prolog constitutional framework:

Article Alignment
I — Human Autonomy The user sets, overrides, and abandons goals at will. The agent proposes; the user decides. Goal commands (/goal abandon, /goal block) are always available.
II — Transparency All goal progress is logged in context.json. The agent states what it's doing and why at every evaluation checkpoint. No silent work.
III — Harm Prevention The goal system does not execute destructive actions autonomously. It evaluates criteria and proposes tasks — execution still requires tool approval per existing permission model.
VI — Accountability Every goal state transition (set, progress, achieved, blocked, abandoned) is recorded with timestamp and reason. Full audit trail in context.json and Neo4j.
VIII — Sustainability The audio alarm has a fallback chain and does not consume resources when not alerting. Goal evaluation is lightweight (read JSON, check booleans).
XI — Continuous Improvement The goal system itself is a mechanism for improvement — each completed goal advances the project. Reflective re-planning allows the agent to learn from failed tasks within a session.

REQ-023-001: The goal system SHALL NOT execute destructive actions autonomously — it SHALL evaluate criteria and propose tasks, and execution SHALL still require tool approval per the existing permission model (Article III — Harm Prevention).


User Scenarios & Stories

US-001: Set a Session Goal (P0)

As a developer I want to define a measurable goal at session start So that the agent knows what to work toward and I can track progress

Acceptance Criteria:


US-002: Continuous Progress Evaluation (P0)

As a developer I want the agent to automatically check progress after every significant action So that it keeps working toward the goal without me having to ask

Acceptance Criteria:


US-003: Goal Persistence Across Compaction (P0)

As a developer I want the goal to survive context compaction and session restarts So that the agent never forgets what we're working toward

Acceptance Criteria:


US-004: Audio Alarm on Achievement or Block (P1)

As a developer who steps away from the terminal I want an audio alarm when the goal is achieved or the agent is blocked So that I know when to come back without watching the screen

Acceptance Criteria:


US-005: Stop Hook — Prevent Premature Stopping (P0)

As a developer I want the agent to check the goal before it stops responding So that it continues working instead of going silent

Acceptance Criteria:


US-006: Reflective Re-planning (P1)

As a developer I want the agent to re-plan when a task fails or a criterion regresses So that it adapts instead of repeating the same failed approach

Acceptance Criteria:


US-007: Goal Lifecycle Commands (P1)

As a developer I want commands to manage the goal lifecycle So that I have full control over what the agent is pursuing

Acceptance Criteria:


Data Models

Goal Structure in context.json
{
  "state": {
    "active_session": 412,
    "goal": {
      "id": "goal-412-001",
      "statement": "All CI tests pass at 100% pass rate, 90%+ coverage, zero hardcoded values",
      "status": "active",
      "set_at": "2026-04-03T16:00:00Z",
      "achieved_at": null,
      "abandoned_at": null,
      "criteria": [
        {
          "id": "c1",
          "description": "CI test pass rate = 100%",
          "status": "pending",
          "verify_command": "ci/local-ci.sh test",
          "verify_pattern": "Tests passed:\\s+(\\d+)",
          "met_at": null
        },
        {
          "id": "c2",
          "description": "Coverage >= 90%",
          "status": "pending",
          "verify_command": "ci/local-ci.sh coverage",
          "verify_pattern": "TOTAL.*?(\\d+)%",
          "met_at": null
        },
        {
          "id": "c3",
          "description": "Lint clean (black, isort, flake8)",
          "status": "pending",
          "verify_command": "ci/local-ci.sh lint",
          "verify_pattern": null,
          "met_at": null
        }
      ],
      "tasks": [
        {
          "id": "t1",
          "description": "Fix Neo4j connection failures",
          "criteria": ["c1"],
          "status": "done",
          "created_at": "2026-04-03T16:00:00Z",
          "done_at": "2026-04-03T17:30:00Z"
        }
      ],
      "progress": [
        {
          "at": "2026-04-03T16:30:00Z",
          "action": "CI run",
          "note": "11554/11793 passing — Redis hardcoding fixed",
          "criteria_changed": {"c3": "met"}
        }
      ],
      "blockers": [],
      "retry_counts": {}
    }
  }
}
State Transitions
            /goal set
    [none] ──────────> [active]
                          |
              +-----------+-----------+
              |           |           |
         all criteria   /goal block  /goal abandon
            met           |           |
              |           v           v
              v       [blocked]   [abandoned]
          [achieved]      |
              |      /goal unblock
              |           |
              |           v
              |       [active]
              v
           (alarm)
Pydantic Models
class GoalCriterion(BaseModel):
    id: str
    description: str
    status: Literal["pending", "met", "failed"] = "pending"
    verify_command: str | None = None
    verify_pattern: str | None = None
    met_at: datetime | None = None

class GoalTask(BaseModel):
    id: str
    description: str
    criteria: list[str]
    status: Literal["pending", "in_progress", "done", "failed"] = "pending"
    created_at: datetime = Field(default_factory=datetime.now)
    done_at: datetime | None = None

class GoalProgress(BaseModel):
    at: datetime = Field(default_factory=datetime.now)
    action: str
    note: str
    criteria_changed: dict[str, str] = Field(default_factory=dict)

class Goal(BaseModel):
    id: str
    statement: str
    status: Literal["active", "achieved", "blocked", "abandoned"] = "active"
    set_at: datetime = Field(default_factory=datetime.now)
    achieved_at: datetime | None = None
    abandoned_at: datetime | None = None
    criteria: list[GoalCriterion] = Field(default_factory=list)
    tasks: list[GoalTask] = Field(default_factory=list)
    progress: list[GoalProgress] = Field(default_factory=list)
    blockers: list[str] = Field(default_factory=list)
    retry_counts: dict[str, int] = Field(default_factory=dict)

Audio Alarm System

Sound Patterns
Event Pattern Frequencies Duration
Goal achieved 3 ascending tones 600, 800, 1000 Hz 0.2s, 0.2s, 0.3s
Agent blocked 2 low tones, repeated 300, 300 Hz 0.3s, 0.3s
Criterion met Single tone 800 Hz 0.2s
Criterion regressed Descending tone 500, 300 Hz 0.2s, 0.3s

REQ-023-039: The system SHALL play the sound pattern defined for each event: goal achieved — 3 ascending tones at 600, 800 and 1000 Hz for 0.2s, 0.2s and 0.3s; agent blocked — 2 low tones at 300 Hz repeated for 0.3s each; criterion met — a single 800 Hz tone for 0.2s; criterion regressed — a descending tone at 500 Hz then 300 Hz for 0.2s and 0.3s.

Backend Fallback Chain
  1. ffplay -nodisp -autoexit -f lavfi -i "sine=f={freq}:d={dur}" (ffmpeg)
  2. paplay /usr/share/sounds/freedesktop/stereo/complete.oga (PulseAudio)
  3. aplay <generated wav> (ALSA)
  4. mpv --no-video <generated wav> (mpv)
  5. python3 -c "import sys; sys.stdout.write('\a'); sys.stdout.flush()" (terminal bell)

Detection at startup: probe each backend, cache the first working one.

Repeat Logic

REQ-023-040: On achievement the alarm SHALL play once and then every 30 seconds until the user sends a message; on blocked it SHALL play once and then every 60 seconds until the user sends a message.

REQ-023-041: The alarm repeat SHALL be a background process that checks the flag file /tmp/orchestrata-alarm-active, and a user message received via the UserPromptSubmit hook SHALL remove the flag file and stop the alarm.


Functional Requirements

FR-001: Goal Persistence

REQ-023-042: The system SHALL persist all goal state in context.json including statement, criteria, tasks, progress, and blockers.

REQ-023-043: The goal SHALL survive session restarts, context compaction, and conversation truncation.

FR-002: Goal Injection at Session Start

REQ-023-044: The SessionStart hook SHALL read the goal from context.json and inject it into the conversation.

REQ-023-045: If an active goal exists, the hook SHALL display the goal statement and all criteria with current status indicators ([x] for met, [ ] for pending).

FR-003: Continuous Progress Evaluation

REQ-023-046: After every CI run, test execution, or code modification, the system SHALL automatically evaluate all goal criteria. The evaluation SHALL NOT require user intervention and SHALL be triggered by session events.

FR-004: Exit Criterion Validation

REQ-023-047: Each exit criterion SHALL be validated by executing its verify_command and matching against its verify_pattern.

REQ-023-048: The system SHALL transition criterion status from pending to met when the pattern matches successfully.

FR-005: Stop Hook Goal Guard

REQ-023-049: The Stop hook SHALL prevent the agent from stopping when an active goal exists with unachieved criteria.

REQ-023-050: The hook SHALL inject a continue message and signal continuation instead of allowing the stop.

FR-006: Audio Alarm on Completion

REQ-023-051: When all exit criteria are met, the system SHALL play a success audio alarm.

REQ-023-052: When the goal becomes blocked, the system SHALL play an attention audio alarm.

REQ-023-053: The alarm SHALL persist until the user sends a message.

FR-007: Goal Lifecycle Commands

REQ-023-054: The system SHALL support /goal commands for set, status, achieved, abandon, block, and unblock operations.

REQ-023-055: All commands SHALL update context.json atomically and SHALL provide user feedback.

FR-008: Reflective Re-planning

REQ-023-056: When a task fails or a criterion regresses, the system SHALL evaluate alternative approaches.

REQ-023-057: After 3 consecutive failures on the same task, the system SHALL mark the goal as blocked with a reason.

FR-009: Blocker Detection and Notification

REQ-023-058: The system SHALL detect blockers that prevent goal progress. Blockers MAY be auto-detected (network failures, permission errors) or user-defined via /goal block.

REQ-023-059: When blocked, the system SHALL trigger the attention alarm.

FR-010: Goal State Machine

REQ-023-060: The system SHALL enforce goal state transitions according to the defined state machine: none → active → (achieved|blocked|abandoned). Invalid transitions SHALL be rejected.

FR-011: Progress Logging

REQ-023-061: Every goal state change SHALL be logged as a progress entry with timestamp, action, notes, and criteria changes.

REQ-023-062: Progress SHALL be stored in context.json and MAY be persisted to Neo4j.

FR-012: Criteria Regression Handling

REQ-023-063: When a previously met criterion regresses to failed status, the system SHALL log the regression, announce it to the user, and trigger re-planning to address the regression.

FR-013: Audio Backend Detection

REQ-023-064: The system SHALL detect the first available audio backend at startup using the fallback chain: ffplay, paplay, aplay, mpv, terminal bell.

REQ-023-065: The detected backend SHALL be cached for subsequent use.

FR-014: Context JSON Integrity

REQ-023-066: The goal field in context.json SHALL maintain referential integrity: task criteria references SHALL match existing criterion IDs.

REQ-023-067: Invalid references SHALL be rejected during goal creation.

FR-015: Multi-session Goal Visibility

REQ-023-068: An active goal SHALL be visible across all sessions within the same project.

REQ-023-069: New Claude Code sessions SHALL receive the goal via session hooks, not via conversation memory.

FR-016: Alarm Non-Blocking

REQ-023-070: Audio alarms SHALL NOT block agent output or tool execution.

REQ-023-071: Alarms SHALL run as background processes with a flag file to coordinate state.

FR-017: Goal Abandonment Tracking

REQ-023-072: When a goal is abandoned, the system SHALL log the abandonment reason, timestamp, and SHALL NOT auto-resume.

REQ-023-073: Abandoned goals SHALL be displayable via /goal status.


Error Conditions

ID Condition Handling
ERR-001 Goal set with blank statement Reject with error "Goal statement cannot be blank", maintain no active goal
ERR-002 Criterion has no verify_command or verify_pattern Allow creation with warning, criterion can only transition via /goal achieved
ERR-003 Goal state transition to invalid state Reject transition, log error, maintain current state
ERR-004 No audio backend available Log warning, disable audio alarms, continue with terminal bell only
ERR-005 context.json goal field is corrupted JSON Fallback to no active goal, log error to system logs
ERR-006 Stop hook cannot read goal from context.json Allow stop (existing behavior), log error, flag for manual review
ERR-007 All criteria remain pending after 100 task completions Log warning "Goal may be mis-specified", continue evaluation
ERR-008 Goal ID collision during goal creation Generate new unique ID with timestamp suffix, log warning
ERR-009 Task references non-existent criterion ID Reject task creation, return error with valid criterion IDs
ERR-010 Goal evaluation timeout after 30 seconds Log timeout error, continue to next evaluation cycle
ERR-011 Alarm process cannot be spawned Log error to system logs, continue without audio
ERR-012 Flag file /tmp/orchestrata-alarm-active cannot be written Disable alarm repeat, play alarm once only
ERR-013 User prompt during alarm repeat Attempt to kill alarm process, log success/failure
ERR-014 Neo4j persistence fails for goal state Continue with context.json only, log error to system logs
ERR-015 Re-planning generates no new tasks after 3 failures Mark goal as blocked with reason "No alternative approaches found"
ERR-016 Goal achievement with conflicting criterion statuses Log error, require manual resolution via /goal achieved override
ERR-017 Session start with corrupted goal progress entries Filter invalid entries, continue with valid entries, log warning
ERR-018 Alarm backend probe fails for all backends Fall back to terminal bell (\a), log all backend failures
ERR-019 Goal criterion verify_command execution fails Log failure, maintain pending status, continue with next criterion
ERR-020 Multiple concurrent goal updates (race condition) Last write wins, log warning about concurrent modification

REQ-023-074: ERR-001 — When a goal is set with a blank statement, the system SHALL reject it with the error "Goal statement cannot be blank" and SHALL maintain no active goal.

REQ-023-075: ERR-002 — When a criterion has no verify_command or verify_pattern, the system SHALL allow its creation with a warning, and that criterion SHALL be transitionable only via /goal achieved.

REQ-023-076: ERR-003 — When a goal state transition targets an invalid state, the system SHALL reject the transition, log the error, and maintain the current state.

REQ-023-077: ERR-004 — When no audio backend is available, the system SHALL log a warning, disable audio alarms, and continue with the terminal bell only.

REQ-023-078: ERR-005 — When the goal field in context.json is corrupted JSON, the system SHALL fall back to no active goal and log the error to the system logs.

REQ-023-079: ERR-006 — When the Stop hook cannot read the goal from context.json, it SHALL allow the stop (existing behavior), log the error, and flag it for manual review.

REQ-023-080: ERR-007 — When all criteria remain pending after 100 task completions, the system SHALL log the warning "Goal may be mis-specified" and SHALL continue evaluation.

REQ-023-081: ERR-008 — On a goal ID collision during goal creation, the system SHALL generate a new unique ID with a timestamp suffix and log a warning.

REQ-023-082: ERR-009 — When a task references a non-existent criterion ID, the system SHALL reject the task creation and return an error carrying the valid criterion IDs.

REQ-023-083: ERR-010 — When goal evaluation times out after 30 seconds, the system SHALL log the timeout error and continue to the next evaluation cycle.

REQ-023-084: ERR-011 — When an alarm process cannot be spawned, the system SHALL log the error to the system logs and continue without audio.

REQ-023-085: ERR-012 — When the flag file /tmp/orchestrata-alarm-active cannot be written, the system SHALL disable the alarm repeat and play the alarm once only.

REQ-023-086: ERR-013 — On a user prompt during an alarm repeat, the system SHALL attempt to kill the alarm process and SHALL log the success or failure.

REQ-023-087: ERR-014 — When Neo4j persistence fails for goal state, the system SHALL continue with context.json only and log the error to the system logs.

REQ-023-088: ERR-015 — When re-planning generates no new tasks after 3 failures, the system SHALL mark the goal as blocked with the reason "No alternative approaches found".

REQ-023-089: ERR-016 — On goal achievement with conflicting criterion statuses, the system SHALL log the error and require manual resolution via the /goal achieved override.

REQ-023-090: ERR-017 — On session start with corrupted goal progress entries, the system SHALL filter the invalid entries, continue with the valid entries, and log a warning.

REQ-023-091: ERR-018 — When the alarm backend probe fails for all backends, the system SHALL fall back to the terminal bell (\a) and log all backend failures.

REQ-023-092: ERR-019 — When a goal criterion verify_command execution fails, the system SHALL log the failure, maintain the pending status, and continue with the next criterion.

REQ-023-093: ERR-020 — On multiple concurrent goal updates (race condition), last write SHALL win and the system SHALL log a warning about the concurrent modification.


API Contracts

SessionController.goal_set(statement: str, criteria: list[dict]) -> Goal

Creates a new active goal with the provided statement and criteria.

Parameters:

Returns:

Exceptions:

SessionController.goal_evaluate() -> dict[str, str]

Evaluates all active goal criteria against their verification commands and patterns.

Returns:

Side Effects:

SessionController.goal_status() -> dict

Returns complete goal status including statement, criteria with status, tasks, and progress.

Returns:

SessionController.goal_achieve(reason: str = "Manually achieved") -> bool

Manually marks the goal as achieved and triggers success alarm.

Parameters:

Returns:

SessionController.goal_abandon(reason: str) -> bool

Abandons the active goal without achieving it.

Parameters:

Returns:

SessionController.goal_block(reason: str) -> bool

Marks the active goal as blocked and triggers attention alarm.

Parameters:

Returns:

SessionController.goal_unblock() -> bool

Clears blocked status from the active goal.

Returns:

AudioAlarm.play_success_alarm() -> bool

Plays the success alarm pattern (3 ascending tones).

Returns:

AudioAlarm.play_blocked_alarm() -> bool

Plays the blocked alarm pattern (2 low repeating tones).

Returns:

AudioAlarm.cancel_alarms() -> bool

Cancels all active alarm processes.

Returns:

HookArchitecture.session_start_goal_injection() -> str

Injects goal information into session start output.

Returns:

HookArchitecture.stop_hook_goal_check() -> bool

Checks goal status before allowing agent stop.

Returns:

REQ-023-094: SessionController SHALL expose the goal API with the parameters, return values, side effects and exceptions defined in this section: goal_set(statement: str, criteria: list[dict]) -> Goal, goal_evaluate() -> dict[str, str], goal_status() -> dict, goal_achieve(reason: str) -> bool, goal_abandon(reason: str) -> bool, goal_block(reason: str) -> bool, and goal_unblock() -> bool.

REQ-023-095: AudioAlarm SHALL expose play_success_alarm() -> bool, play_blocked_alarm() -> bool and cancel_alarms() -> bool, and the hook layer SHALL expose session_start_goal_injection() -> str and stop_hook_goal_check() -> bool, with the return semantics defined in this section.


Non-Functional Requirements

Performance
Availability
Security
Scalability
Maintainability
Reliability
Usability

Technical Design

Architecture Pattern

The goal system implements the BDI (Belief-Desire-Intention) agent architecture:

Belief Layer: context.json state containing current system status (test counts, branch, coverage)

Desire Layer: Goal statement with exit criteria defining what the user wants achieved

Intention Layer: Active goal with committed tasks defining what the agent will do about it

Data Flow
1. User sets goal → /goal set → SessionController.goal_set()
   ↓
2. Goal stored in context.json
   ↓
3. Session start → Hook reads context.json → Injects goal into conversation
   ↓
4. Work proceeds → Events trigger goal_evaluate()
   ↓
5. Evaluation checks criteria → Updates status → Creates progress entries
   ↓
6. If all criteria met → goal_achieve() → Play success alarm
   ↓
7. If blocked → goal_block() → Play blocked alarm
   ↓
8. If user sends message → Cancel alarms
Storage Design
Event Triggers
State Machine Implementation
Audio Alarm Architecture
Alarm Triggered
    ↓
Detect Backend (probe ffplay → paplay → aplay → mpv → bell)
    ↓
Write Flag File (/tmp/orchestrata-alarm-active)
    ↓
Spawn Background Process
    ↓
Play Pattern (repeat every 30s/60s)
    ↓
User Message Received → Cancel Alarm
    ↓
Remove Flag File
Hook Integration Points

Security

Input Validation
Audit Logging
Access Control
Data Protection
Threat Model

Integration Points

Session Management (Spec 006)
Context System
Audio System
CI/CD Integration

REQ-023-097: local-ci.sh results SHALL be parsed for criterion evaluation: test pass/fail counts extracted from JUnit XML, coverage reports parsed for threshold verification, and lint output checked for clean status.

Claude Code Hooks
Neo4j Database (Optional)

REQ-023-098: Goal state persisted to Neo4j SHALL use Goal nodes with a CONTAINS relationship to criteria and a HAS_TASK relationship to task nodes, and SHALL support cross-session goal-history queries and goal-achievement-rate analytics.


Hook Architecture

SessionStart: Goal Injection
session_auto_start.py
+-- Read context.json
+-- If state.goal exists and status == "active":
|   +-- Output: "## Active Goal"
|   +-- Output: goal.statement
|   +-- Output: criteria with [x]/[ ] status
|   +-- Output: "Continue working toward this goal."
+-- If no goal or goal not active:
    +-- Output: "No active goal. Use /goal set <statement> to define one."

REQ-023-099: When no goal exists or the goal is not active, the SessionStart hook SHALL output No active goal. Use /goal set <statement> to define one.

Stop: Goal Guard
goal_check_hook.py (new, registered on Stop event)
+-- Read context.json
+-- If no active goal: exit (allow stop)
+-- Evaluate all criteria:
    +-- If all met: mark achieved, play success alarm, allow stop
    +-- If blocked: play blocked alarm, allow stop
    +-- If criteria remain and no blockers:
        +-- Output: "Goal not achieved. Remaining criteria: [list]"
        +-- Output: "Resuming work."
        +-- Exit with continue signal

REQ-023-100: When the Stop hook evaluates all criteria and finds them all met, it SHALL mark the goal achieved, play the success alarm and allow the stop; when the goal is blocked, it SHALL play the blocked alarm and allow the stop.

UserPromptSubmit: Alarm Cancellation
session_close_hook.py (existing, add alarm check)
+-- If /tmp/orchestrata-alarm-active exists:
    +-- Remove flag file
    +-- Kill alarm background process

Examples

Example 1: Setting a Goal
User: /goal set "Complete CI pipeline with 100% test pass rate"
Agent: I'll help you define measurable criteria for this goal.
        Exit Criterion 1: All CI tests pass
        Exit Criterion 2: Coverage >= 90%
        Exit Criterion 3: Code passes all linting
        [Continue interactively...]
User: Accept these criteria
Agent: Goal set! Active: "Complete CI pipeline with 100% test pass rate"
       Criteria:
       [ ] All CI tests pass
       [ ] Coverage >= 90%
       [ ] Code passes all linting
Example 2: Progress Evaluation
Agent: Running CI tests... 11554/11793 tests passing
       Coverage report: 87.5%
       
       Goal Evaluation:
       ❌ Criterion 1: Tests pass (239 failures remain)
       ❌ Criterion 2: Coverage < 90%
       ✅ Criterion 3: Lint clean
       
       Continuing work toward goal...
Example 3: Goal Achievement
Agent: Running CI tests... 11793/11793 tests passing
       Coverage report: 92.3%
       
       Goal Evaluation:
       ✅ All criteria met!
       
       [SUCCESS ALARM PLAYS]
       
       Goal achieved! "Complete CI pipeline with 100% test pass rate"
       Achieved at: 2026-04-09T14:30:00Z
Example 4: Stop Hook Prevention
Agent: [User sends nothing, system prepares to stop]
       
       Stop Hook: Active goal detected!
       Goal not achieved. Remaining criteria:
       - All CI tests pass (123 failures)
       - Coverage >= 90% (currently 87.5%)
       
       Resuming work toward goal...
Example 5: Reflective Re-planning
Agent: Task "Fix Neo4j connection" failed after 3 attempts
       
       Re-planning triggered:
       Alternative approach: Use SQLite fallback
       New task: "Implement SQLite persistence layer"
       Alternative approach: Mock Neo4j for development
       New task: "Create test doubles for Neo4j"
       
       [ALARM: Goal blocked - no viable alternatives after 3 failed tasks]

Success Criteria

The following criteria MUST be met for this spec to be considered complete:

Phase 1: Data Model and CRUD (Day 1)
  1. Add Goal, GoalCriterion, GoalTask, GoalProgress models to session models
  2. Add goal field to ProjectState model
  3. Add goal operations to SessionController
  4. Add /goal skill to Claude Code hooks
  5. Tests: goal CRUD, persistence, state transitions
Phase 2: Session Injection (Day 1)
  1. Modify session_auto_start.py to read and display active goal
  2. Goal prompt when no goal is set
  3. Tests: injection at session start, after compaction
Phase 3: Continuous Evaluation (Day 2)
  1. Add goal_evaluate() method that checks criteria
  2. Integrate with CI results parsing (read JUnit XML, extract pass/fail/coverage)
  3. Auto-evaluate after ci/local-ci.sh runs
  4. Progress logging
  5. Tests: evaluation triggers, criterion transitions, progress entries
Phase 4: Stop Hook Guard (Day 2)
  1. Create goal_check_hook.py registered on Stop event
  2. Goal state check logic
  3. Continue signal when goal not achieved
  4. Tests: stop prevention, stop allowance when achieved/blocked
Phase 5: Audio Alarm (Day 2)
  1. Backend detection (probe ffplay, paplay, aplay, mpv)
  2. Tone generation for each pattern
  3. Repeat logic with flag file
  4. Alarm cancellation on user message
  5. Tests: backend detection, alarm trigger, cancellation
Phase 6: Reflective Re-planning (Day 3)
  1. Failure detection after task execution
  2. Re-planning logic (propose alternative tasks)
  3. Retry counting with 3-strike block
  4. Tests: re-planning triggers, retry limits
Phase 7: Neo4j Integration (Day 3)
  1. Persist goal lifecycle to Neo4j (Goal node, CONTAINS criteria, HAS_TASK relationships)
  2. Query goal history across sessions
  3. Tests: Neo4j persistence, cross-session queries

Testing Requirements

Test Framework and Approach
Unit Testing Requirements
FR-001 through FR-017 Coverage

REQ-023-143: Each functional requirement MUST have corresponding unit tests:

Goal Model Tests (FR-001, FR-014)

Goal Persistence Tests (FR-001)

Evaluation Tests (FR-003, FR-004, FR-012)

Audio Alarm Tests (FR-006, FR-013, FR-016)

Command Tests (FR-007)

Pydantic Model Validation Tests
def test_goal_criterion_validation():
    """Test GoalCriterion model validates fields correctly"""
    
def test_goal_task_validation():
    """Test GoalTask model enforces criteria references"""
    
def test_goal_progress_validation():
    """Test GoalProgress model requires timestamp and action"""
Integration Testing Requirements
Hook Integration Tests
Session Management Integration (Spec 006)
CI/CD Integration Tests
End-to-End Testing Requirements
US-001 through US-007 Scenarios

REQ-023-144: Each user story MUST have end-to-end tests simulating real usage:

US-001: Set Session Goal (P0)

def test_e2e_set_session_goal():
    """End-to-end: User sets goal, agent decomposes into criteria"""
    # Simulate: session start → /goal set → criteria definition → goal active

US-002: Continuous Progress Evaluation (P0)

def test_e2e_continuous_progress_evaluation():
    """End-to-end: Agent evaluates progress automatically after actions"""
    # Simulate: task → CI run → criterion evaluation → progress log

US-003: Goal Persistence (P0)

def test_e2e_goal_persistence_across_compaction():
    """End-to-end: Goal survives context compaction"""
    # Simulate: set goal → compact context → restart session → goal still active

US-004: Audio Alarm (P1)

def test_e2e_audio_alarm_on_achievement():
    """End-to-end: Success alarm plays when goal achieved"""
    # Simulate: all criteria met → alarm plays → user message cancels
    
def test_e2e_audio_alarm_on_block():
    """End-to-end: Attention alarm plays when blocked"""
    # Simulate: goal blocked → alarm plays → user message cancels

US-005: Stop Hook (P0)

def test_e2e_stop_hook_prevents_premature_stopping():
    """End-to-end: Stop hook prevents agent from stopping"""
    # Simulate: active goal → prepare to stop → stop hook injects continue

US-006: Reflective Re-planning (P1)

def test_e2e_reflective_replanning_on_failure():
    """End-to-end: Agent re-plans after task failure"""
    # Simulate: task fails → re-plan → new tasks → 3 strikes blocks goal

US-007: Goal Lifecycle Commands (P1)

def test_e2e_goal_lifecycle_commands():
    """End-to-end: All /goal commands work correctly"""
    # Simulate: set → status → achieve/abandon/block → unblock
Performance Testing Requirements
FR-016 Performance Benchmarks
Load Testing
def test_performance_goal_evaluation():
    """Test goal evaluation completes within 30 seconds with 50 criteria"""
    
def test_performance_context_json_write():
    """Test context.json goal update completes within 1 second"""
    
def test_performance_audio_backend_detection():
    """Test backend detection completes within 2 seconds"""
Test Data Management
Test Fixtures
Context.json Test Files
Audio Test Files
Test Environment Requirements
Audio Backend Testing
File System Requirements
Database Testing
Code Coverage Requirements
Minimum Coverage Thresholds

REQ-023-145: Line-coverage minimums SHALL be met: goal system modules 95%, session controller 90%, audio alarm system 85% (hardware-dependent), hook architecture 90%, overall system 90%.

Coverage Exclusions

REQ-023-146: Coverage measurement SHALL exclude audio backend probe failures, actual audio playback, and Neo4j unavailability.

Test Automation Requirements
Pre-commit Hook

REQ-023-147: The pre-commit hook SHALL run the goal system unit tests, enforce the 90% coverage threshold, and validate JSON schema conformity.

CI/CD Integration
# Required CI commands
python -m pytest tests/test_goal_system/ -v --cov=src/goal_system --cov-report=term-missing

REQ-023-148: CI SHALL run python -m pytest tests/test_goal_system/ -v --cov=src/goal_system --cov-report=term-missing.

Test Reporting

REQ-023-149: Test runs SHALL generate JUnit XML for CI integration, HTML coverage reports for developer review, and test execution timing reports for performance monitoring.

Error Condition Testing
ERR-001 through ERR-020 Coverage

REQ-023-150: Each error condition MUST have tests verifying proper handling:

def test_err001_blank_goal_statement():
    """Test ERR-001: Reject blank goal statement"""
    
def test_err002_criterion_no_verify_command():
    """Test ERR-002: Allow criterion without verify command with warning"""
    
def test_err005_corrupted_context_json():
    """Test ERR-005: Handle corrupted goal field gracefully"""
    
def test_err019_verify_command_execution_fails():
    """Test ERR-019: Handle verification command failure"""
Regression Testing
Context Compaction Regression
Session Restart Regression
Multi-session Goal Visibility

Verification

Test Categories
Exit Criteria for This Spec

Observability

Logging Requirements
  1. Component Logging
    • Log all major operations with appropriate log levels
    • Include correlation IDs for request tracing
    • Log performance metrics for critical operations
    • Log errors with full context for debugging

REQ-023-151: The goal system SHALL log all major operations with appropriate log levels, include correlation IDs for request tracing, log performance metrics for critical operations, and log errors with full context for debugging.

Metrics Requirements
  1. Performance Metrics
    • Operation duration histograms
    • Request/error rate counters
    • Resource utilization gauges
    • Business metrics relevant to domain

REQ-023-152: The goal system SHALL expose performance metrics: operation duration histograms, request/error rate counters, resource utilization gauges, and business metrics relevant to the domain.

Tracing Requirements
  1. Distributed Tracing
    • Trace propagation across component boundaries
    • Span attributes for domain-specific context
    • Trace sampling based on operational needs

REQ-023-153: The goal system SHALL support distributed tracing: trace propagation across component boundaries, span attributes for domain-specific context, and trace sampling based on operational needs.

Alerting Requirements
  1. Critical Alerts
    • Error rate spikes
    • Performance degradation
    • Resource exhaustion
    • Business metric anomalies

REQ-023-154: The goal system SHALL raise critical alerts on error rate spikes, performance degradation, resource exhaustion, and business metric anomalies.

Dashboard Requirements
  1. Operational Dashboard
    • Real-time system health
    • Performance trends
    • Error analysis
    • Resource monitoring

REQ-023-155: The goal system SHALL provide an operational dashboard covering real-time system health, performance trends, error analysis, and resource monitoring.


Revision History

Version Date Author Changes
1.0.0 2026-04-09 Mohamed Initial specification for Goal-Driven Session System implementing BDI architecture with audio alarms, continuous progress evaluation, and session persistence