Symphony Terminal States for Issues: Configuration and Usage Guide
Symphony treats five default states—Closed, Cancelled, Canceled, Duplicate, and Done—as terminal states that indicate an issue is finished and should no longer be considered for further work.
In the openai/symphony repository, terminal states are a core configuration concept that determines when an issue lifecycle ends. These states prevent the orchestrator from reopening, reassiging, or processing issues that have reached completion. By default, Symphony ships with a predefined set of terminal states embedded in the configuration schema, though users can override these values in their application configuration.
Default Terminal States in Symphony
Symphony defines terminal states as string values that represent irreversible completion statuses. Unless explicitly customized, the system recognizes the following five states as terminal:
Closed– The issue has been formally closed and archived.Cancelled– The issue was cancelled before completion (Commonwealth spelling).Canceled– Alternative spelling of "Cancelled" (American spelling).Duplicate– The issue duplicates another existing issue.Done– The work associated with the issue is complete.
These defaults ensure compatibility with common project management workflows while accounting for spelling variations across different English locales.
Configuration Schema Location
The default terminal states are declared in elixir/lib/symphony_elixir/config/schema.ex within the Tracker embedded schema. The terminal_states field uses an array of strings with a hardcoded default list:
field(:terminal_states, {:array, :string},
default: ["Closed", "Cancelled", "Canceled", "Duplicate", "Done"])
This schema definition (lines 53–55) establishes the baseline configuration that the application uses when no user overrides exist. The SymphonyElixir.Config.Schema module validates these entries during application startup, ensuring all terminal states are properly formatted strings.
Runtime Access and Usage
During execution, the orchestrator retrieves the configured terminal states via the runtime configuration system. In elixir/lib/symphony_elixir/orchestrator.ex, the code accesses these values at lines 646–647 using:
Config.settings!().tracker.terminal_states
Internally, the orchestrator likely implements a terminal_state_set/0 function (as referenced in the source) that converts this list into a MapSet for O(1) membership testing. This pattern allows efficient filtering when processing large batches of issues:
terminal_states = Config.settings!().tracker.terminal_states
if MapSet.member?(MapSet.new(terminal_states), normalize_issue_state(issue.state)) do
Logger.info("Issue is terminal – no further processing")
end
Customizing Terminal States
Users can override the default terminal states by specifying a custom list in their config.exs or runtime configuration. This customization occurs under the :tracker key, alongside other tracker-specific settings like active_states and project_slug.
To customize, define your preferred terminal states in the configuration map:
%{
tracker: %{
kind: "linear",
api_key: "$LINEAR_API_KEY",
project_slug: "my-project",
active_states: ["Todo", "In Progress"],
terminal_states: ["Closed", "Cancelled", "Done", "Won't Fix"]
}
}
When overriding, you must include all desired terminal states explicitly—the configuration does not merge with defaults. Any state not listed in terminal_states will be treated as active and eligible for processing by the orchestrator.
Summary
- Symphony defines five default terminal states:
Closed,Cancelled,Canceled,Duplicate, andDone. - Defaults are hardcoded in
elixir/lib/symphony_elixir/config/schema.ex(lines 53–55) within theTrackerembedded schema. - The orchestrator accesses these states at runtime via
Config.settings!().tracker.terminal_states(lines 646–647 inorchestrator.ex). - Users can override defaults in
config.exsby specifying a customterminal_statesarray under the:trackerconfiguration key. - Terminal states prevent further processing, while all other states are considered active and eligible for workflow operations.
Frequently Asked Questions
Can I add custom terminal states like "Won't Fix" or "Resolved"?
Yes. You can define any custom terminal states in your configuration file by listing them in the terminal_states array under the :tracker key. When overriding defaults, include all states you want treated as terminal—both standard and custom—as the configuration system uses your explicit list rather than merging with built-in defaults.
What is the difference between active_states and terminal_states in Symphony?
active_states defines which issue states indicate work is currently in progress or ready to be started, while terminal_states identifies when work has permanently ended. The orchestrator uses these lists to filter issues: it processes active states and ignores terminal states. Both configurations are optional, but defining them explicitly prevents ambiguity in workflow automation.
Why does Symphony include both "Cancelled" and "Canceled" as defaults?
The configuration includes both spellings—Commonwealth ("Cancelled") and American ("Canceled")—to maximize compatibility with external issue trackers like Linear, GitHub, or Jira that might use either spelling convention. This prevents issues from being incorrectly classified as active simply due to regional spelling differences. If your organization standardizes on one spelling, you can override the defaults to include only your preferred variant.
How does Symphony normalize issue state names when checking against terminal states?
According to the source code patterns, Symphony likely implements a normalize_issue_state/1 function that standardizes casing and formatting before checking membership in the terminal state set. This ensures that states like "closed" or "CLOSED" match against the configured "Closed" value, though the exact normalization logic depends on your specific tracker adapter implementation in the SymphonyElixir namespace.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →