All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
1.9.0 - 2026-04-26
- OpenCode CLI agent adapter: configure with
agent.kind: opencodefor autonomous issue-to-code workflows using the OpenCode CLI viaopencode run --format json. Supports fork-per-turn execution, JSON event normalization, SSH remote dispatch, permission policy synthesis, token accounting, and companion deployment examples viaexamples/docker/opencode.Dockerfileandexamples/WORKFLOW.opencode.md. (#476, #478, #479)
- SSH worker command assembly: multi-token remote commands are now
appended verbatim instead of shell-quoted as a single word, so remote
agent launches such as
codex app-serverand other pre-formed shell fragments no longer fail withcommand not found. (#493) - GitHub and Jira tracker adapters no longer return partially populated issues, slices, or state maps when tracked fetch operations fail; the nil-on-error contract is preserved for issue detail and state lookups. (PR #496)
1.8.0 - 2026-04-17
- Codex CLI agent adapter: configure with
agent.kind: codexfor autonomous issue-to-code workflows using OpenAI Codex CLI via thecodex app-serverJSON-RPC 2.0 protocol. Supports the same structured lifecycle as Claude Code and Copilot CLI adapters — event normalization, token tracking, timeout enforcement, graceful SIGTERM→SIGKILL shutdown, and session resume viaResumeSessionID. Tool calls are serialized through a channel to prevent concurrent stdin corruption. Handshake reads are cancellable via context, preventing stalled subprocesses from hanging the worker indefinitely. (#238)
1.7.1 - 2026-04-15
- CLI:
--versionnow outputs a single diagnostic line including commit SHA, build date, Go version, and OS/architecture — e.g.sortie 1.7.0 (commit: a1b2c3d, built: 2026-04-15, go1.26.1, linux/amd64). The previous GNU-style copyright/warranty block is removed. Build tooling (Makefile,Dockerfile,.goreleaser.yaml, and the release workflow) now injectsCommitandDatevia-ldflagsat all build sites.
- Orchestrator:
sortie_ci_escalations_totalover-counted during CI escalation.escalateCIFailureincremented the metric unconditionally before calling the tracker API, then incremented again on error — producing two increments for one failed operation. It also incremented whenTrackerAdapterwas nil, recording a phantom escalation that was never performed. Both defects are fixed; the metric now increments exactly once per operation outcome, matching the pattern inescalateReviewFailure. (#449)
1.7.0 - 2026-04-13
- Cross-retry session resume: continuation retries now propagate the session ID from the exiting worker through the retry entry so the next worker can resume the agent conversation instead of starting a fresh session. The session ID is persisted to SQLite and restored on startup recovery. (#207)
- Token usage cost estimation on the dashboard and JSON API: operators
configure per-adapter token rates in WORKFLOW.md front matter
(
token_ratesblock); the dashboard surfaces per-session and aggregate USD cost estimates computed from running sessions. The JSON API includesactive_estimated_cost_usdwhen token rates are configured. (#436) - Dashboard accordion tables: Running Sessions, Retry Queue, and Run History tables use an expand/collapse accordion pattern. Primary status columns are visible at a glance; secondary detail expands on click. Expansion state survives the 5-second auto-refresh via sessionStorage. (#432, #444)
StderrCollectorbuffer hardening: agent stderr collection now uses a 10 MiB scanner buffer cap and a head/tail ring-buffer retention strategy with a configurable byte budget, preventing silent line truncation and unbounded memory growth during long agent turns. (#387)
- Retry timer tracker validation:
HandleRetryTimernow callsFetchIssueByIDinstead of scanning all candidate issues viaFetchCandidateIssues, reducing each retry timer fire from O(pages) tracker API calls to exactly one. (#206)
- 009: Add nullable
session_id TEXTcolumn toretry_entries
1.6.1 - 2026-04-11
- Runtime terminal workspace sweep: workspace directories for issues that reach a terminal tracker state after their worker has exited are now cleaned up periodically by the event loop. This closes the gap between the startup sweep and in-flight reconciliation, preventing unbounded disk accumulation on long-running instances. (#428)
- Orchestrator:
needs-human-reviewsoft-stop now correctly triggers the handoff transition. Previously, theSoftStopbranch inHandleWorkerExitmatched all soft-stop reasons before the handoff case was reached, leaving the issue active and causing an infinite re-dispatch loop. (#426)
1.6.0 - 2026-04-10
- Self-review loop before PR creation: the orchestrator generates a workspace
diff, executes configurable verification commands (tests, linters), assembles
a structured review prompt, and iterates with the agent up to a configurable
cap before proceeding. Opt-in via the
self_review:block in WORKFLOW.md front matter (max_iterations,verify_commands,diff_max_bytes). (#312) - PR review comment routing: when a reviewer requests changes on an
agent-created PR, the orchestrator detects
CHANGES_REQUESTEDreviews, extracts the review comments, and dispatches a continuation turn so the agent can address feedback automatically. Configurable viareactions.review_commentsin WORKFLOW.md (max_retries,debounce_ms,escalation,escalation_label). IncludesSCMAdapterdomain interface for PR and review operations with a GitHub Checks/Reviews API implementation. (#305) - Unified
reactionsconfig block in WORKFLOW.md for event-driven continuation triggers.reactions.ci_failurereplaces the top-levelci_feedbackkey (which remains supported for backward compatibility). Each reaction type sharesprovider,max_retries,escalation, andescalation_labelfields. (#418) - Windows process lifecycle support for agent adapters and workspace hooks.
Agent subprocesses are now placed in Windows Job Objects with
JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE, enabling full process tree cleanup on timeout or cancellation. Graceful shutdown sendsCTRL_BREAK_EVENTto the process group; force-terminate usesTerminateJobObject. Workspace hooks execute viacmd.exe /Con Windows with their own Job Object for timeout enforcement. Theprocutilpackage exposes cross-platform functions —SignalGraceful,AssignProcess,CleanupProcess,SetProcessGroup,KillProcessGroup— andWasSignaledis now platform-aware. Adapters no longer referencesyscall.SIGTERMdirectly. (#390, #391)
- CI pending backoff base now derives from the operator-configured
poll_intervalinstead of a hardcoded 10 s default. A 30 s poll interval produces a(60 s, 120 s, 240 s, 300 s…)backoff schedule. Falls back to 10 s whenpoll_intervalis zero or negative. (#385)
ci_feedbacktop-level config key in WORKFLOW.md. Usereactions.ci_failureinstead. The legacy key continues to work; when both are present,reactions.ci_failuretakes precedence. (#418)
- Workflow Manager continued using the pre-reconfiguration logger after
logging.levelwas applied from WORKFLOW.md extensions, causing reload diagnostics to use the wrong log level. The Manager now updates its logger after every reconfiguration. (#394) - Reaction dispatch fingerprinting:
MarkReactionDispatchedwas called at schedule time rather than actual dispatch time. If the process restarted between scheduling and dispatch, the fingerprint was permanently marked dispatched while the retry entry was lost, silencing future CI-fix reactions for that SHA. (#420) - Config: non-string YAML values in
reactionsfields (provider,escalation,escalation_label) now produce aConfigErrorinstead of silently coercing to an empty string. (#423) install.sh: detect Rosetta 2 on macOS and prefer the nativearm64binary overamd64. (#391)
- 007: Add nullable
review_metadata TEXTcolumn torun_history - 008: Add
reaction_fingerprintstable for cross-restart reaction deduplication
1.5.1 - 2026-04-08
- GNU-style CLI help output with grouped sections, column-aligned
descriptions, usage examples, and a "Learn more" link. Short aliases
-h(help) and-V(version) are now recognized. Help text prints to stdout instead of stderr. Covers all three commands:sortie,sortie validate,sortie mcp-server. (#398)
- Copilot CLI adapter: prefix
--additional-mcp-configfile paths with@to match the documented Copilot CLI syntax. Bare file paths worked in Copilot CLI ≤1.0.18 via an undocumented fallback that was removed in v1.0.21, causingInvalid JSON in --additional-mcp-configon every turn. Operator-providedcopilot-cli.mcp_configvalues are now auto-detected: inline JSON is passed unchanged,@-prefixed paths are preserved, and bare file paths receive the@prefix automatically. (#404) - Agent adapters: reclassify exit-code-0 turns with zero output tokens
and no
resultevent asturn_failedinstead ofturn_completed. Previously, when an agent subprocess crashed immediately (e.g., MCP config parse error) but exited 0, all turns were counted as successful, causing the orchestrator to exhaustmax_turnsand trigger a false-positive handoff transition. Failed turns now retry with exponential backoff. Applies to both Claude Code and Copilot CLI adapters. (#404)
1.5.0 - 2026-04-07
- Always-on HTTP server with default port 7678 (mnemonic: SORT on T9).
The server now starts unconditionally; the
--portflag overrides the default but no longer acts as an activation trigger. Pass--port=0to disable. Prometheus metrics, health probes, and dashboard are available out of the box without flags. --hostCLI flag andserver.hostworkflow config field for configurable bind address. Default127.0.0.1; container deployments override with--host 0.0.0.0. Resolution order: CLI flag > config > default.--log-formatCLI flag with valuestext(default) andjson. JSON format emits one JSON object per log line withtime,level,msg, and structured fields (issue_id,session_id, etc.) for integration with Loki, Datadog, CloudWatch, and ELK.- Dockerfile: multi-stage build producing a distroless container image
with only
/usr/bin/sortie. Users consume viaCOPY --from=ghcr.io/sortie-ai/sortie:latest /usr/bin/sortie /usr/bin/sortiein their own Dockerfile. Build flags match.goreleaser.yaml:CGO_ENABLED=0,-trimpath,-s -w, tagsosusergo,netgo. .dockerignoreexcluding build artifacts,.git, test fixtures, and documentation.- Agent-specific example Dockerfiles:
docker/claude-code.Dockerfileanddocker/copilot.Dockerfilewith non-root user, health checks, and volume mounts. - Kubernetes deployment examples:
k8s/deployment.yaml(Recreate strategy, liveness/readiness probes on/livezand/readyz),k8s/configmap.yaml,k8s/service.yaml,k8s/pvc.yaml. - Grafana dashboard template at
grafana-dashboard.jsoncovering all 22 Prometheus metrics. Panels fordispatch_transitions_total,tracker_comments_total,ci_status_checks_total, andci_escalations_totaladded in dedicated CI Feedback and Integration rows. Uses__inputs/DS_PROMETHEUSpattern for portable data source selection.
- Agent stderr is now surfaced at WARN level when a turn fails instead
of DEBUG. Both Claude Code and Copilot CLI adapters buffer stderr
during a turn and log at WARN on non-zero exit, making startup
rejections (e.g.,
--dangerously-skip-permissionsunder root) visible at default log level. Successful turns continue to log stderr at DEBUG.
1.4.0 - 2026-04-04
- CI feedback loop: when a CI pipeline fails on an agent-created branch,
the orchestrator detects the failure, injects the CI failure logs into
the next agent turn, and dispatches a continuation session so the agent
can diagnose and fix the issue automatically. Controlled by a new
ci_feedbackconfig section inWORKFLOW.md(kind,max_retries,max_log_lines,escalation). Feature activation follows kind-based convention: presentci_feedback.kindenables, absent disables. CIStatusProviderdomain interface: adapter contract for fetching CI check status from an SCM platform. Returns structuredCIResultwith overall status (pending/passing/failing), individual check runs, and an optional log excerpt from the first failing check.- GitHub
CIStatusProviderimplementation via the Checks API: fetches check runs for a git ref, computes aggregate status, and retrieves truncated log output from the first failing GitHub Actions job. Log fetching is controlled bymax_log_lines(0 disables). ANSI escape sequences are stripped from log output. - CI failure escalation: when
ci_feedback.max_retriesis exceeded, the orchestrator applies a configurable escalation action -- add a label (defaultneeds-human) or post a comment on the issue. - Exponential backoff for CI pending re-enqueue:
reconcileCIStatusnow appliesbase * 2^attemptsbackoff (capped at 5 minutes) when CI checks remain pending or on transient API errors, reducing GitHub Checks API request volume from ~120 to ~15 per 20-minute CI run per issue. Stale pending entries expire after a 30-minute TTL. TrackerOpsWgshutdown drain: fire-and-forget tracker API goroutines (comment posting, label adding) are now tracked by a dedicatedsync.WaitGroupand drained during graceful shutdown with a 35-second timeout, preventing orphaned goroutines on process exit.- Automatic credential merging: when
ci_feedback.kindmatchestracker.kind, the orchestrator merges tracker credentials (api_key,project,endpoint) into the CI provider adapter config at startup, eliminating the need to duplicate credentials in a pass-through block.
1.3.0 - 2026-04-03
- MCP tool execution channel: agents can now call registered tools at
runtime via the Model Context Protocol. The worker generates
.sortie/mcp.jsonper session and passes it to the agent runtime via--mcp-config(Claude Code) or--additional-mcp-config(Copilot CLI). The agent runtime spawnssortie mcp-serveras a stdio sidecar; the orchestrator does not manage the sidecar lifecycle. sortie mcp-serversubcommand: MCP stdio JSON-RPC server that exposes registeredAgentToolimplementations viatools/listandtools/call. Constructs its ownTrackerAdapterandToolRegistryby re-reading WORKFLOW.md from an absolute path passed via--workflow.sortie_statusMCP tool (Tier 1): returns live session runtime metadata -- current turn number, remaining turns, attempt number, session duration, and cumulative token usage. Reads from.sortie/state.json, a worker-written file updated at session start, each turn start, and on token usage events.workspace_historyMCP tool (Tier 1): returns up to 10 most recent completed run attempts for the current issue from therun_historySQLite table. Opens the database in read-only mode (?mode=ro). Non-fatal on database open failure -- the MCP server continues with other tools available.- Agent-to-orchestrator file protocol: agents can write
blockedorneeds-human-reviewto.sortie/statusto suppress continuation retries. The orchestrator reads the file after each turn and before the tracker state refresh. Absent, unrecognized, or unreadable files degrade to normal behavior. Symlinks on either path component are rejected viaLstat. RuntimeStatusSuffixauto-injection: the orchestrator appends A2O protocol instructions to the first-turn prompt so agents know how to signal blocked status without workflow author intervention. Continuation turns omit the suffix.- Soft-stop exit path in
HandleWorkerExit: when the worker exits with a recognized status file signal, the orchestrator releases the claim and suppresses continuation retry. The issue re-dispatches only on tracker state change. - Operator MCP config merging: if
mcp_configis set in WORKFLOW.md, the worker merges the operator's config with thesortie-toolsentry. Name collision onsortie-toolsis a validation error.
- Agent-to-orchestrator file protocol specification
(
docs/agent-to-orchestrator-protocol.md): 9-section normative document covering file format, recognized values, read timing, cleanup lifecycle, symlink rejection, and conformance checklist. - ADR-0009: MCP stdio sidecar for tool execution -- documents the chosen transport mechanism, process model, credential handling, adapter integration, and alternatives analysis.
- Architecture Section 10.4 rewrite:
AgentToolinterface contract,ToolRegistryinvariants, tier classification framework, andtracker_apitool specification aligned with implementation.
1.2.1 - 2026-04-01
- Prevent re-dispatch loop when effort budget (
agent.max_sessions) is exhausted for an issue; the orchestrator now records a durable budget-exhaustion guard so the dispatch loop does not restart the issue on the next tick - Persist and display
turns_completedper run in the dashboard and run history table - Show fully qualified
owner/repo#Ndisplay identifiers for GitHub issues in the dashboard and API instead of bare issue numbers - Pass
handoff_statetofindCurrentStateLabel,extractState,normalizeIssue, andnormalizeBlockersin the GitHub adapter soTransitionIssueaccepts the handoff state and stale labels are removed during transitions - Rename dashboard footer cache label from "Cache:" to "Cache Read:" and add explanatory tooltips in the footer and Running Sessions table
- Defer
token_usageevent emission in the Claude adapter when an assistant message carries zero output tokens (tool_use-only messages in Claude Code 2.xstream-jsonformat); the adapter now accumulates input tokens and falls back to the result event which carries correct totals
- 004: Add index
idx_run_history_issue_idonrun_history(issue_id) - 005: Add
turns_completed INTEGER NOT NULL DEFAULT 0torun_history - 006: Add nullable
display_identifiercolumn torun_history
1.2.0 - 2026-03-31
- GitHub Copilot CLI adapter: configure with
agent.kind: copilotfor fully automated issue-to-code workflows using GitHub's headless Copilot CLI. Supports local execution and SSH remote dispatch viaworker.ssh_hosts. Tool scope is controlled byallowed_tools,denied_tools,available_tools, andexcluded_tools;--allow-allis the default when none are set. Session continuity across turns via--resume. Authentication uses token env vars when present, falling back togh auth status. worker.ssh_strict_host_key_checking: new optional worker config field controlling OpenSSHStrictHostKeyCheckingfor remote SSH agent sessions. Acceptsaccept-new(default, Trust On First Use),yes(strict verification, requires a pre-populatedknown_hosts), orno(disable host-key checking). Applies to both the Claude Code and Copilot CLI adapters.
1.1.0 - 2026-03-30
- GitHub Issues tracker adapter: configure with
tracker.kind: githubandtracker.project: OWNER/REPO. State management is label-based;TransitionIssueapplies and removes GitHub labels with convergent retry on partial failure. - GitHub adapter: in-memory ETag cache for reconciliation polls —
If-None-Matchconditional requests return304 Not Modifiedon unchanged issues, reducing GitHub API rate limit consumption during active runs. sortie validateGitHub adapter config validation: emits diagnostics fortracker.projectformat (OWNER/REPO),GITHUB_TOKENenvironment variable hint, empty state labels, and active/terminal state label overlap. Errors block dispatch; warnings are advisory.
install.sh: checksum verification used substring matching (grep | awk) that could accept a checksum entry for the wrong archive entry; now uses exact field matching (awk '$2 == f').
1.0.0 - 2026-03-29
- SPDX JSON Software Bill of Materials (SBOM) included with every release
archive, generated via
syftin the GoReleaser pipeline for supply-chain auditing.
0.0.10 - 2026-03-28
sortie validatetemplate static analysis: three advisory warning classes —WarnDotContext(top-level key referenced inside{{ range }}or{{ with }}where dot is redefined),WarnUnknownVar(variable not in the{issue, attempt, run}contract), andWarnUnknownField(valid top-level key with an unknown sub-field, including depth-4+ field chains on known level-3 scalars). Warnings appear in both text and JSON output without blocking dispatch or changing the exit code.sortie validatefront matter schema validation: detects unknown top-level keys, unknown sub-keys within known sections, type mismatches, and semantic issues (non-positivehooks.timeout_ms, non-numericmax_concurrent_agents_by_stateentries). Field paths are included in every diagnostic so operators can locate the offending key. Warnings are advisory only.SORTIE_*environment variable config overrides: any workflow front matter key can be overridden via aSORTIE_-prefixed environment variable (e.g.,SORTIE_POLLING_INTERVAL_MS=5000). Non-empty real env vars take precedence over.envfile values. Raw line content is removed from.envparse errors and override values are excluded from debug logs to prevent secret leakage.- Orchestrator: tracker comments posted at session lifecycle points — session start, successful completion, and failure — with run duration and attempt metadata. Comments fire from a detached goroutine to avoid blocking the event loop.
- Orchestrator: issues are transitioned to the configured
in_progress_stateon dispatch, with a no-op skip when the issue is already in the target state.sortie_dispatch_transitions_totalPrometheus counter trackssuccess,error, andskippedoutcomes.
0.0.9 - 2026-03-27
sortie validatesubcommand for one-shot workflow file validation without starting the orchestrator, opening the database, or spawning a filesystem watcher. Supports--format text(stderr diagnostics) and--format json(structured stdout output) for CI pipelines and pre-commit hooks. Flag-parse errors are routed through the diagnostics emitter.--dry-runflag for a single read-only poll cycle that validates the full startup sequence (workflow load, preflight, database, adapter wiring) without dispatching work or persisting state.--log-levelflag andlogging.levelworkflow extension key to set the minimum log severity at startup (debug,info,warn,error).- Dashboard: Workflow column in Active Sessions table and a new Run History
table showing completed session outcomes, timing, and workflow file.
SQL migration 003 adds a nullable
workflow_filecolumn torun_history. - Workspace root write-permission check in dispatch preflight — surfaces a clear diagnostic instead of failing mid-dispatch.
- Homebrew tap distribution via GoReleaser-managed tap repository
(
brew install sortie-ai/tap/sortie). - Jira adapter:
User-Agentheader (sortie/<version>) sent on every HTTP request. - Claude Code adapter: per-request
APIDurationMSontoken_usageevents for API-call-level latency visibility, clamped to a minimum of 1 ms. - Claude Code adapter: tool error text now included in
EventToolResult.Message.
- CLI: adapters implementing
io.Closerare now closed during graceful shutdown, preventing resource leaks. - Orchestrator:
TurnCountincrements onsession_startedinstead of session finalization, correctly reflecting in-progress turns. - Claude Code adapter: tool error messages stripped of XML markup and tail-truncated to prevent oversized events.
0.0.8 - 2026-03-26
- JSON API server with
GET /api/v1/state,GET /api/v1/<identifier>, andPOST /api/v1/refreshendpoints for programmatic access to orchestrator state. Enabled via--portflag orserver.portconfig. - HTML dashboard at
/with auto-refreshing view of running sessions, retry queue, token totals, and runtime statistics when the HTTP server is enabled. /livezand/readyzhealth endpoints following Kubernetes z-pages conventions./readyzchecks database accessibility, preflight validation, and workflow loading.- Prometheus
/metricsendpoint exposing session gauges, dispatch/worker/retry counters, token counters, tracker request counters, tool call counters, poll and worker duration histograms, andsortie_build_info. Uses a dedicatedprometheus.Registry— compatible with standard Prometheus scrape configs. tracker_apiclient-side tool: agents can query the tracker during sessions to fetch issues and comments, scoped to the configured project.- SSH worker extension via
worker.ssh_hostsconfig: dispatch agent runs to remote hosts over SSH with round-robin host selection and per-host concurrency limits (worker.max_concurrent_agents_per_host). - Per-session token breakdown in JSON API and dashboard:
input_tokens,output_tokens,cache_creation_tokens,cache_read_tokens. - Per-session timing breakdown in JSON API and dashboard:
elapsed,agent_time,idle_time,agent_pct. - Claude Code adapter:
tool_resultevents now emitted, making agent tool invocations visible in the dashboard and API. - Worker failure logging in
HandleWorkerExit: WARN withnext_attemptanddelay_msfor retryable errors, ERROR for non-retryable errors. - Structured logging:
issue_id,issue_identifier, andsession_idcontext fields now present on all orchestrator lifecycle log lines. Agent tool calls logged at INFO level. - POSIX-compatible install script (
install.sh) for automated binary installation.
POST /api/v1/refreshreturns409 Conflictduring graceful shutdown instead of accepting requests that cannot be fulfilled.
- Claude Code adapter: duplicate
token_usageevents no longer emitted when assistant-level usage is already reported in the result message. - HTTP server:
405 Method Not Allowedresponses now include theAllowheader per RFC 9110. - Jira adapter:
sortie_tracker_requests_totalcounter no longer increments on no-op calls with empty ID lists.
0.0.7 - 2026-03-24
- Graceful shutdown: on SIGTERM/SIGINT the orchestrator now drains running workers (up to 30 s), persists final state to SQLite, flushes pending agent events, and cancels retry timers before exiting.
- Issue handoff via
tracker.handoff_stateconfig field — when an agent session completes normally and the issue is still in an active state, the orchestrator transitions it to the configured handoff state (e.g., "In Review") and skips the continuation retry. TransitionIssueoperation on theTrackerAdapterinterface — Jira adapter uses the workflow transitions API; file adapter uses an in-memory override map.- Per-issue effort budget via
agent.max_sessions— limits total agent sessions dispatched per issue before releasing the claim. Default 0 (unlimited). - Documentation site at https://docs.sortie-ai.com/ with initial configuration reference.
- Orchestrator: continuation retry attempt counter now increments correctly across sessions instead of resetting to 1 on every normal exit.
- CLI: orchestrator-only fields (
max_turns,max_concurrent_agents,max_retry_backoff_ms,max_concurrent_agents_by_state) removed from the adapter config map, fixing silent shadowing of adapter extension keys such asclaude-code.max_turns. - Jira adapter:
extractStringSlicenow handles[]stringfrom the config layer — previously only[]anywas handled, silently reverting to default states and causing configuredactive_states/terminal_statesto be ignored. - Jira adapter:
FetchIssueStatesByIDsnow queries by numericidinstead ofkey, and results are keyed by issue ID, fixing reconciliation failures where state changes on running issues were never detected. - Jira adapter: non-numeric IDs are now rejected instead of silently mangled,
and empty ID lists no longer produce invalid
id IN ()JQL. - File and Jira adapters now return
ErrTrackerNotFoundfor missing issues inFetchIssueByIDandFetchIssueComments. - Orchestrator: INFO-level tick summary log after each dispatch cycle with candidate, dispatched, running, and retrying counters to distinguish normal operation from a stall.
0.0.6 - 2026-03-23
- Orchestrator engine with state management, concurrency-limited dispatch, worker lifecycle, exponential-backoff retry scheduling, active-run reconciliation, and event-driven poll loop with graceful shutdown.
- Full startup sequence: workflow load, preflight validation, database open, state reconciliation, and poll loop — in that order.
- Dispatch preflight checks that validate adapter availability, required API keys, and agent configuration before dispatching work.
- Adapter metadata via
AdapterMetaandRegisterWithMetaso adapters can declare requirements (e.g.,RequiresAPIKey) checked during preflight. - Retry classification on
TrackerErrorKindandAgentErrorKind— errors are now classified as retryable or permanent for dispatch decisions. ErrTrackerNotFounderror kind for HTTP 404 responses from tracker adapters.- Configurable
db_pathfield in workflow configuration with~and$VARexpansion. - Workflow validation callback (
ValidateFunc) that guards config promotion during hot-reload.
- Workspace
CleanupByPathnow rejects non-canonical paths and uses the actual workspace path for pending cleanup instead of reconstructing it from config. - Startup: preflight checks now run before opening the database, preventing
.sortie.dbcreation when configuration is invalid. - Startup:
.sortie.dbis now created adjacent to WORKFLOW.md instead of in the working directory.
0.0.5 - 2026-03-21
- Workspace manager: safe path computation from issue identifiers with containment validation and symlink rejection.
- Workspace manager: atomic directory creation and reuse with
CreatedNowflag for hook gating. - Workspace hook execution with configurable timeout, truncated output
capture, and restricted subprocess environment (only
PATH,HOME,SHELL, andSORTIE_*variables are inherited). - Workspace lifecycle orchestration:
Prepare,Finish, andCleanupfunctions that sequenceafter_create,before_run,after_run, andbefore_removehooks with appropriate failure semantics (fatal vs best-effort) andcontext.WithoutCancelfor teardown hooks. - Batch workspace cleanup (
CleanupTerminal) for removing terminal-state issue workspaces with per-identifier error collection and best-effortbefore_removehook execution. ListWorkspaceKeysfor enumerating workspace directory names under a root, skipping non-directories and symlinks.
0.0.4 - 2026-03-20
AgentAdapterinterface and normalized event model: 13 event types,TokenUsage,AgentConfig,Session,TurnResult, andAgentErrorwith 9 error kinds.- Agent adapter registry (
registry.Agents) for registration and lookup by kind. - Mock agent adapter (kind
"mock") with configurable turn outcomes, delays, and cumulative token accumulation for orchestrator and integration testing. - Claude Code agent adapter (kind
"claude-code") that launches the CLI as a subprocess, reads JSONL events from stdout, and normalizes them to domain event types. Supports graceful SIGTERM→SIGKILL shutdown on context cancellation and session resumption viaResumeSessionID.
- Claude Code adapter: double-wait race between
RunTurnandStopSession—gracefulKillis now fire-and-forget with timer-based SIGKILL escalation. - Claude Code adapter: error on missing binary now includes the actual command name instead of a hardcoded string.
0.0.3 - 2026-03-20
- Normalized
Issuemodel andTrackerAdapterinterface for multi-tracker support. - Typed adapter registry with thread-safe registration and lookup.
- File-based tracker adapter for local JSON task definitions.
- Jira Cloud REST API v3 adapter with cursor-based paginated search, issue detail retrieval, state tracking, and comment fetching.
- BFS flattener for Atlassian Document Format (ADF) descriptions to plain text.
- JQL builder with string escaping and optional
query_filterclause support. query_filterfield in tracker configuration for custom JQL expressions.- GoReleaser configuration for reproducible cross-platform binary releases (linux/darwin/windows, amd64/arm64).
- Jira search endpoint migrated from retired
/rest/api/3/searchto/rest/api/3/search/jql(Atlassian returns 410 Gone on the old endpoint). - Infinite loop guard in Jira comment pagination when the API returns inconsistent offsets.
0.0.2 - 2026-03-19
- SQLite persistence layer with WAL mode and single-writer enforcement.
- Schema migration runner with versioned SQL files.
- CRUD operations for retry entries, run history, session metadata, and aggregate metrics.
- Startup recovery loader that resumes incomplete retry entries on restart.
- Deterministic ordering for session metadata queries via
session_idtie-breaker.
0.0.1 - 2026-03-18
- WORKFLOW.md file loader with YAML front matter and prompt body parsing.
- Typed configuration layer with
$VARenvironment variable resolution and~home directory expansion. - Prompt template engine using Go
text/templatein strict mode (unknown variables and filters cause hard errors). - Turn-based prompt builder for multi-turn agent conversations.
- Filesystem watcher for live WORKFLOW.md reload via
fsnotify. - CLI entry point (
sortie) with graceful shutdown and signal handling.
- Environment variable expansion now preserves inline
$VARreferences inside URIs instead of silently dropping them. - Fractional float values no longer silently coerced to integers during config parsing.
0.0.0 - 2026-03-18
- Go module scaffold and project directory structure.
- Structured logging built on
log/slogwith issue-aware and session-aware contextual fields. - CI pipeline with
golangci-lint,gofmtenforcement, and test execution via GitHub Actions. - Architecture Decision Records (ADR-0001 through ADR-0005).