Configuration
Generated model reference
The model reference below is generated from the public Pydantic models. Field types, defaults, and constraints come directly from the source models; update those models rather than maintaining a parallel field table here.
Runtime settings
curupira.models.configuration.ExecutionSettings
pydantic-model
Bases: ValidatedModel
Shared scheduling, workspace, persistence, and process limits.
Attributes:
| Name | Type | Description |
|---|---|---|
max_active_tasks |
int
|
Maximum number of coding-agent tasks running concurrently. |
max_pending_tasks |
int
|
Maximum number of discovered tasks waiting to run. |
workspace_dir |
Path
|
Default directory for repository checkouts and worktrees. |
state_db_path |
Path
|
SQLite database path for durable task and schedule state. |
otlp_endpoint |
AnyHttpUrl | None
|
Optional OTLP/HTTP endpoint for task trace export. |
task_timeout_seconds |
PositiveSeconds | None
|
Optional time limit for one coding-agent task. |
max_output_bytes |
int
|
Maximum captured output per subprocess stream. |
polling |
PollingSettings
|
Discovery polling intervals and fetch limits. |
Show JSON schema:
{
"$defs": {
"PollingSettings": {
"additionalProperties": false,
"description": "Global discovery intervals and GitHub query size.\n\nAttributes:\n poll_interval_seconds: Delay between discovery polls, in seconds.\n batch_size: Maximum number of GitHub items fetched by one poll.\n cron_poll_interval_seconds: Maximum delay between cron schedule checks.",
"properties": {
"poll_interval_seconds": {
"default": 30.0,
"exclusiveMinimum": 0,
"title": "Poll Interval Seconds",
"type": "number"
},
"batch_size": {
"default": 100,
"maximum": 1000,
"minimum": 1,
"title": "Batch Size",
"type": "integer"
},
"cron_poll_interval_seconds": {
"default": 1.0,
"exclusiveMinimum": 0,
"maximum": 60,
"title": "Cron Poll Interval Seconds",
"type": "number"
}
},
"title": "PollingSettings",
"type": "object"
}
},
"additionalProperties": false,
"description": "Shared scheduling, workspace, persistence, and process limits.\n\nAttributes:\n max_active_tasks: Maximum number of coding-agent tasks running concurrently.\n max_pending_tasks: Maximum number of discovered tasks waiting to run.\n workspace_dir: Default directory for repository checkouts and worktrees.\n state_db_path: SQLite database path for durable task and schedule state.\n otlp_endpoint: Optional OTLP/HTTP endpoint for task trace export.\n task_timeout_seconds: Optional time limit for one coding-agent task.\n max_output_bytes: Maximum captured output per subprocess stream.\n polling: Discovery polling intervals and fetch limits.",
"properties": {
"max_active_tasks": {
"default": 1,
"maximum": 1000,
"minimum": 1,
"title": "Max Active Tasks",
"type": "integer"
},
"max_pending_tasks": {
"default": 100,
"maximum": 10000,
"minimum": 1,
"title": "Max Pending Tasks",
"type": "integer"
},
"workspace_dir": {
"format": "path",
"title": "Workspace Dir",
"type": "string"
},
"state_db_path": {
"format": "path",
"title": "State Db Path",
"type": "string"
},
"otlp_endpoint": {
"anyOf": [
{
"format": "uri",
"minLength": 1,
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Otlp Endpoint"
},
"task_timeout_seconds": {
"anyOf": [
{
"exclusiveMinimum": 0,
"type": "number"
},
{
"type": "null"
}
],
"default": null,
"title": "Task Timeout Seconds"
},
"max_output_bytes": {
"default": 1000000,
"maximum": 100000000,
"minimum": 1024,
"title": "Max Output Bytes",
"type": "integer"
},
"polling": {
"$ref": "#/$defs/PollingSettings"
}
},
"title": "ExecutionSettings",
"type": "object"
}
Fields:
-
max_active_tasks(int) -
max_pending_tasks(int) -
workspace_dir(Path) -
state_db_path(Path) -
otlp_endpoint(AnyHttpUrl | None) -
task_timeout_seconds(PositiveSeconds | None) -
max_output_bytes(int) -
polling(PollingSettings)
Validators:
-
expand_path→workspace_dir,state_db_path
max_active_tasks
pydantic-field
max_pending_tasks
pydantic-field
workspace_dir
pydantic-field
state_db_path
pydantic-field
otlp_endpoint = None
pydantic-field
task_timeout_seconds = None
pydantic-field
max_output_bytes
pydantic-field
polling
pydantic-field
curupira.models.configuration.PollingSettings
pydantic-model
Bases: ValidatedModel
Global discovery intervals and GitHub query size.
Attributes:
| Name | Type | Description |
|---|---|---|
poll_interval_seconds |
PositiveSeconds
|
Delay between discovery polls, in seconds. |
batch_size |
int
|
Maximum number of GitHub items fetched by one poll. |
cron_poll_interval_seconds |
PositiveSeconds
|
Maximum delay between cron schedule checks. |
Show JSON schema:
{
"additionalProperties": false,
"description": "Global discovery intervals and GitHub query size.\n\nAttributes:\n poll_interval_seconds: Delay between discovery polls, in seconds.\n batch_size: Maximum number of GitHub items fetched by one poll.\n cron_poll_interval_seconds: Maximum delay between cron schedule checks.",
"properties": {
"poll_interval_seconds": {
"default": 30.0,
"exclusiveMinimum": 0,
"title": "Poll Interval Seconds",
"type": "number"
},
"batch_size": {
"default": 100,
"maximum": 1000,
"minimum": 1,
"title": "Batch Size",
"type": "integer"
},
"cron_poll_interval_seconds": {
"default": 1.0,
"exclusiveMinimum": 0,
"maximum": 60,
"title": "Cron Poll Interval Seconds",
"type": "number"
}
},
"title": "PollingSettings",
"type": "object"
}
Fields:
-
poll_interval_seconds(PositiveSeconds) -
batch_size(int) -
cron_poll_interval_seconds(PositiveSeconds)
poll_interval_seconds = 30.0
pydantic-field
batch_size
pydantic-field
cron_poll_interval_seconds
pydantic-field
model_config = ConfigDict(extra='forbid', frozen=True, validate_default=True)
class-attribute
instance-attribute
Coding-agent defaults and automations
curupira.models.configuration.CodingAgentDefaults
pydantic-model
Bases: ValidatedModel
Profile reference and timezone inherited by automation definitions.
Attributes:
| Name | Type | Description |
|---|---|---|
profile |
Identifier
|
Name of the CLI profile used when an automation does not override it. |
timezone |
NonEmptyString
|
IANA timezone inherited by cron automations without their own timezone. |
Show JSON schema:
{
"additionalProperties": false,
"description": "Profile reference and timezone inherited by automation definitions.\n\nAttributes:\n profile: Name of the CLI profile used when an automation does not override it.\n timezone: IANA timezone inherited by cron automations without their own timezone.",
"properties": {
"profile": {
"default": "opencode",
"minLength": 1,
"pattern": "^[A-Za-z0-9_-]+$",
"title": "Profile",
"type": "string"
},
"timezone": {
"default": "UTC",
"minLength": 1,
"title": "Timezone",
"type": "string"
}
},
"title": "CodingAgentDefaults",
"type": "object"
}
Fields:
Validators:
profile = 'opencode'
pydantic-field
timezone = 'UTC'
pydantic-field
model_config = ConfigDict(extra='forbid', frozen=True, validate_default=True)
class-attribute
instance-attribute
validate_timezone(value)
pydantic-validator
Require a known IANA timezone.
curupira.models.configuration.CodingAgentsSettings
pydantic-model
Bases: ValidatedModel
Named CLI profiles, inherited defaults, and keyed automation definitions.
Attributes:
| Name | Type | Description |
|---|---|---|
defaults |
CodingAgentDefaults
|
Profile and timezone inherited by automations. |
profiles |
dict[Identifier, CliProfile]
|
Non-empty mapping of user-chosen names to provider-specific CLI options. |
automations |
dict[Identifier, AutomationConfiguration]
|
Non-empty mapping of user-chosen names to issue, PR, or cron definitions. |
Show JSON schema:
{
"$defs": {
"ClaudeCodeCliProfile": {
"additionalProperties": false,
"description": "Claude Code options, including native custom-agent selection.\n\nAttributes:\n provider: Discriminator identifying the Claude Code CLI.\n agent: Optional configured Claude Code agent name.\n effort: Optional Claude model effort level.\n permission_mode: Optional Claude Code permission mode.\n permission_prompts: Whether permission prompts are handled by the host or disabled.",
"properties": {
"model": {
"anyOf": [
{
"minLength": 1,
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Model"
},
"provider": {
"const": "claude",
"default": "claude",
"title": "Provider",
"type": "string"
},
"agent": {
"anyOf": [
{
"minLength": 1,
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Agent"
},
"effort": {
"anyOf": [
{
"enum": [
"low",
"medium",
"high",
"xhigh",
"max",
"ultracode"
],
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Effort"
},
"permission_mode": {
"anyOf": [
{
"enum": [
"default",
"acceptEdits",
"plan",
"auto",
"dontAsk",
"bypassPermissions"
],
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Permission Mode"
},
"permission_prompts": {
"anyOf": [
{
"enum": [
"host",
"none"
],
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Permission Prompts"
}
},
"title": "ClaudeCodeCliProfile",
"type": "object"
},
"CodexCliProfile": {
"additionalProperties": false,
"description": "Codex options, including selection of an existing CLI configuration profile.\n\nAttributes:\n provider: Discriminator identifying the Codex CLI.\n agent: Optional configured Codex agent name.\n effort: Optional Codex reasoning effort.\n sandbox: Optional Codex sandbox permission level.\n auto_review: Whether Codex should review changes automatically.",
"properties": {
"model": {
"anyOf": [
{
"minLength": 1,
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Model"
},
"provider": {
"const": "codex",
"default": "codex",
"title": "Provider",
"type": "string"
},
"agent": {
"anyOf": [
{
"minLength": 1,
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Agent"
},
"effort": {
"anyOf": [
{
"enum": [
"low",
"medium",
"high",
"xhigh",
"max",
"ultra"
],
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Effort"
},
"sandbox": {
"anyOf": [
{
"enum": [
"read-only",
"workspace-write",
"danger-full-access"
],
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Sandbox"
},
"auto_review": {
"default": false,
"title": "Auto Review",
"type": "boolean"
}
},
"title": "CodexCliProfile",
"type": "object"
},
"CodingAgentDefaults": {
"additionalProperties": false,
"description": "Profile reference and timezone inherited by automation definitions.\n\nAttributes:\n profile: Name of the CLI profile used when an automation does not override it.\n timezone: IANA timezone inherited by cron automations without their own timezone.",
"properties": {
"profile": {
"default": "opencode",
"minLength": 1,
"pattern": "^[A-Za-z0-9_-]+$",
"title": "Profile",
"type": "string"
},
"timezone": {
"default": "UTC",
"minLength": 1,
"title": "Timezone",
"type": "string"
}
},
"title": "CodingAgentDefaults",
"type": "object"
},
"CronAutomationConfiguration": {
"additionalProperties": false,
"description": "Discover cron occurrences within an optional inclusive date window.\n\nAttributes:\n schedule: Five-field cron expression defining the occurrence schedule.\n timezone: Optional IANA timezone overriding the inherited default.\n start_date: Optional inclusive earliest occurrence; naive values use the effective timezone.\n end_date: Optional inclusive latest occurrence; naive values use the effective timezone.",
"properties": {
"repo": {
"minLength": 1,
"title": "Repo",
"type": "string"
},
"path": {
"anyOf": [
{
"format": "path",
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Path"
},
"setup_script": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Setup Script"
},
"checkout": {
"default": "worktree",
"enum": [
"worktree",
"main"
],
"title": "Checkout",
"type": "string"
},
"prompt": {
"title": "Prompt",
"type": "string"
},
"profile": {
"anyOf": [
{
"minLength": 1,
"pattern": "^[A-Za-z0-9_-]+$",
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Profile"
},
"trigger_type": {
"default": "cron",
"minLength": 1,
"title": "Trigger Type",
"type": "string"
},
"schedule": {
"minLength": 1,
"title": "Schedule",
"type": "string"
},
"timezone": {
"anyOf": [
{
"minLength": 1,
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Timezone"
},
"start_date": {
"anyOf": [
{
"format": "date-time",
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Start Date"
},
"end_date": {
"anyOf": [
{
"format": "date-time",
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "End Date"
}
},
"required": [
"repo",
"prompt",
"schedule"
],
"title": "CronAutomationConfiguration",
"type": "object"
},
"CursorCliProfile": {
"additionalProperties": false,
"description": "Cursor options, including native agent/ask/plan mode selection.\n\nAttributes:\n provider: Discriminator identifying the Cursor CLI.\n agent: Optional Cursor execution mode.\n force: Whether to force execution in a non-interactive environment.\n trust: Whether to trust the current workspace.",
"properties": {
"model": {
"anyOf": [
{
"minLength": 1,
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Model"
},
"provider": {
"const": "cursor",
"default": "cursor",
"title": "Provider",
"type": "string"
},
"agent": {
"anyOf": [
{
"enum": [
"agent",
"ask",
"plan"
],
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Agent"
},
"force": {
"default": false,
"title": "Force",
"type": "boolean"
},
"trust": {
"default": false,
"title": "Trust",
"type": "boolean"
}
},
"title": "CursorCliProfile",
"type": "object"
},
"IssueAutomationConfiguration": {
"additionalProperties": false,
"description": "Discover issues matching a GitHub Search query.",
"properties": {
"repo": {
"minLength": 1,
"title": "Repo",
"type": "string"
},
"path": {
"anyOf": [
{
"format": "path",
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Path"
},
"setup_script": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Setup Script"
},
"checkout": {
"default": "worktree",
"enum": [
"worktree",
"main"
],
"title": "Checkout",
"type": "string"
},
"prompt": {
"title": "Prompt",
"type": "string"
},
"profile": {
"anyOf": [
{
"minLength": 1,
"pattern": "^[A-Za-z0-9_-]+$",
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Profile"
},
"query": {
"minLength": 1,
"title": "Query",
"type": "string"
},
"trigger_type": {
"default": "issue",
"minLength": 1,
"title": "Trigger Type",
"type": "string"
}
},
"required": [
"repo",
"prompt",
"query"
],
"title": "IssueAutomationConfiguration",
"type": "object"
},
"OpenCodeCliProfile": {
"additionalProperties": false,
"description": "OpenCode options, including native custom-agent selection.\n\nAttributes:\n provider: Discriminator identifying the OpenCode CLI.\n agent: Optional configured OpenCode agent name.\n effort: Optional provider-specific effort level.\n auto_approve: Whether OpenCode runs with approval prompts disabled.",
"properties": {
"model": {
"anyOf": [
{
"minLength": 1,
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Model"
},
"provider": {
"const": "opencode",
"default": "opencode",
"title": "Provider",
"type": "string"
},
"agent": {
"anyOf": [
{
"minLength": 1,
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Agent"
},
"effort": {
"anyOf": [
{
"minLength": 1,
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Effort"
},
"auto_approve": {
"default": false,
"title": "Auto Approve",
"type": "boolean"
}
},
"title": "OpenCodeCliProfile",
"type": "object"
},
"PullRequestAutomationConfiguration": {
"additionalProperties": false,
"description": "Discover pull requests matching a GitHub Search query.",
"properties": {
"repo": {
"minLength": 1,
"title": "Repo",
"type": "string"
},
"path": {
"anyOf": [
{
"format": "path",
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Path"
},
"setup_script": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Setup Script"
},
"checkout": {
"default": "worktree",
"enum": [
"worktree",
"main"
],
"title": "Checkout",
"type": "string"
},
"prompt": {
"title": "Prompt",
"type": "string"
},
"profile": {
"anyOf": [
{
"minLength": 1,
"pattern": "^[A-Za-z0-9_-]+$",
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Profile"
},
"query": {
"minLength": 1,
"title": "Query",
"type": "string"
},
"trigger_type": {
"default": "github-cli-pull-requests",
"minLength": 1,
"title": "Trigger Type",
"type": "string"
}
},
"required": [
"repo",
"prompt",
"query"
],
"title": "PullRequestAutomationConfiguration",
"type": "object"
}
},
"additionalProperties": false,
"description": "Named CLI profiles, inherited defaults, and keyed automation definitions.\n\nAttributes:\n defaults: Profile and timezone inherited by automations.\n profiles: Non-empty mapping of user-chosen names to provider-specific CLI options.\n automations: Non-empty mapping of user-chosen names to issue, PR, or cron definitions.",
"properties": {
"defaults": {
"$ref": "#/$defs/CodingAgentDefaults"
},
"profiles": {
"minProperties": 1,
"patternProperties": {
"^[A-Za-z0-9_-]+$": {
"discriminator": {
"mapping": {
"claude": "#/$defs/ClaudeCodeCliProfile",
"codex": "#/$defs/CodexCliProfile",
"cursor": "#/$defs/CursorCliProfile",
"opencode": "#/$defs/OpenCodeCliProfile"
},
"propertyName": "provider"
},
"oneOf": [
{
"$ref": "#/$defs/OpenCodeCliProfile"
},
{
"$ref": "#/$defs/CodexCliProfile"
},
{
"$ref": "#/$defs/ClaudeCodeCliProfile"
},
{
"$ref": "#/$defs/CursorCliProfile"
}
]
}
},
"propertyNames": {
"minLength": 1
},
"title": "Profiles",
"type": "object"
},
"automations": {
"minProperties": 1,
"patternProperties": {
"^[A-Za-z0-9_-]+$": {
"anyOf": [
{
"$ref": "#/$defs/IssueAutomationConfiguration"
},
{
"$ref": "#/$defs/PullRequestAutomationConfiguration"
},
{
"$ref": "#/$defs/CronAutomationConfiguration"
}
]
}
},
"propertyNames": {
"minLength": 1
},
"title": "Automations",
"type": "object"
}
},
"required": [
"automations"
],
"title": "CodingAgentsSettings",
"type": "object"
}
Fields:
-
defaults(CodingAgentDefaults) -
profiles(dict[Identifier, CliProfile]) -
automations(dict[Identifier, AutomationConfiguration])
Validators:
defaults
pydantic-field
profiles
pydantic-field
automations
pydantic-field
model_config = ConfigDict(extra='forbid', frozen=True, validate_default=True)
class-attribute
instance-attribute
validate_references_and_prompts()
pydantic-validator
Check profile references and prompt placeholders.
curupira.models.configuration.IssueAutomationConfiguration
pydantic-model
Bases: GitHubAutomationConfiguration
Discover issues matching a GitHub Search query.
Show JSON schema:
{
"additionalProperties": false,
"description": "Discover issues matching a GitHub Search query.",
"properties": {
"repo": {
"minLength": 1,
"title": "Repo",
"type": "string"
},
"path": {
"anyOf": [
{
"format": "path",
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Path"
},
"setup_script": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Setup Script"
},
"checkout": {
"default": "worktree",
"enum": [
"worktree",
"main"
],
"title": "Checkout",
"type": "string"
},
"prompt": {
"title": "Prompt",
"type": "string"
},
"profile": {
"anyOf": [
{
"minLength": 1,
"pattern": "^[A-Za-z0-9_-]+$",
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Profile"
},
"query": {
"minLength": 1,
"title": "Query",
"type": "string"
},
"trigger_type": {
"default": "issue",
"minLength": 1,
"title": "Trigger Type",
"type": "string"
}
},
"required": [
"repo",
"prompt",
"query"
],
"title": "IssueAutomationConfiguration",
"type": "object"
}
Fields:
-
repo(NonEmptyString) -
path(Path | None) -
setup_script(str | None) -
checkout(Literal['worktree', 'main']) -
prompt(str) -
profile(Identifier | None) -
query(NonEmptyString) -
trigger_type(NonEmptyString)
Validators:
-
validate_setup_script→setup_script -
validate_repository→repo -
expand_path→path -
validate_prompt_syntax→prompt
trigger_type = 'issue'
pydantic-field
model_config = ConfigDict(extra='forbid', frozen=True, validate_default=True)
class-attribute
instance-attribute
repo
pydantic-field
path = None
pydantic-field
setup_script = None
pydantic-field
checkout = 'worktree'
pydantic-field
prompt
pydantic-field
profile = None
pydantic-field
query
pydantic-field
validate_setup_script(value)
pydantic-validator
Require an optional repository-relative script path without traversal.
validate_repository(value)
pydantic-validator
Require the owner/repository format without traversal segments.
expand_path(value)
pydantic-validator
Expand the optional user-relative workspace override.
validate_prompt_syntax(value)
pydantic-validator
Reject empty prompts and invalid template placeholders.
curupira.models.configuration.PullRequestAutomationConfiguration
pydantic-model
Bases: GitHubAutomationConfiguration
Discover pull requests matching a GitHub Search query.
Show JSON schema:
{
"additionalProperties": false,
"description": "Discover pull requests matching a GitHub Search query.",
"properties": {
"repo": {
"minLength": 1,
"title": "Repo",
"type": "string"
},
"path": {
"anyOf": [
{
"format": "path",
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Path"
},
"setup_script": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Setup Script"
},
"checkout": {
"default": "worktree",
"enum": [
"worktree",
"main"
],
"title": "Checkout",
"type": "string"
},
"prompt": {
"title": "Prompt",
"type": "string"
},
"profile": {
"anyOf": [
{
"minLength": 1,
"pattern": "^[A-Za-z0-9_-]+$",
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Profile"
},
"query": {
"minLength": 1,
"title": "Query",
"type": "string"
},
"trigger_type": {
"default": "github-cli-pull-requests",
"minLength": 1,
"title": "Trigger Type",
"type": "string"
}
},
"required": [
"repo",
"prompt",
"query"
],
"title": "PullRequestAutomationConfiguration",
"type": "object"
}
Fields:
-
repo(NonEmptyString) -
path(Path | None) -
setup_script(str | None) -
checkout(Literal['worktree', 'main']) -
prompt(str) -
profile(Identifier | None) -
query(NonEmptyString) -
trigger_type(NonEmptyString)
Validators:
-
validate_setup_script→setup_script -
validate_repository→repo -
expand_path→path -
validate_prompt_syntax→prompt
trigger_type = 'github-cli-pull-requests'
pydantic-field
model_config = ConfigDict(extra='forbid', frozen=True, validate_default=True)
class-attribute
instance-attribute
repo
pydantic-field
path = None
pydantic-field
setup_script = None
pydantic-field
checkout = 'worktree'
pydantic-field
prompt
pydantic-field
profile = None
pydantic-field
query
pydantic-field
validate_setup_script(value)
pydantic-validator
Require an optional repository-relative script path without traversal.
validate_repository(value)
pydantic-validator
Require the owner/repository format without traversal segments.
expand_path(value)
pydantic-validator
Expand the optional user-relative workspace override.
validate_prompt_syntax(value)
pydantic-validator
Reject empty prompts and invalid template placeholders.
curupira.models.configuration.CronAutomationConfiguration
pydantic-model
Bases: AutomationConfigurationBase
Discover cron occurrences within an optional inclusive date window.
Attributes:
| Name | Type | Description |
|---|---|---|
schedule |
NonEmptyString
|
Five-field cron expression defining the occurrence schedule. |
timezone |
NonEmptyString | None
|
Optional IANA timezone overriding the inherited default. |
start_date |
datetime | None
|
Optional inclusive earliest occurrence; naive values use the effective timezone. |
end_date |
datetime | None
|
Optional inclusive latest occurrence; naive values use the effective timezone. |
Show JSON schema:
{
"additionalProperties": false,
"description": "Discover cron occurrences within an optional inclusive date window.\n\nAttributes:\n schedule: Five-field cron expression defining the occurrence schedule.\n timezone: Optional IANA timezone overriding the inherited default.\n start_date: Optional inclusive earliest occurrence; naive values use the effective timezone.\n end_date: Optional inclusive latest occurrence; naive values use the effective timezone.",
"properties": {
"repo": {
"minLength": 1,
"title": "Repo",
"type": "string"
},
"path": {
"anyOf": [
{
"format": "path",
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Path"
},
"setup_script": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Setup Script"
},
"checkout": {
"default": "worktree",
"enum": [
"worktree",
"main"
],
"title": "Checkout",
"type": "string"
},
"prompt": {
"title": "Prompt",
"type": "string"
},
"profile": {
"anyOf": [
{
"minLength": 1,
"pattern": "^[A-Za-z0-9_-]+$",
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Profile"
},
"trigger_type": {
"default": "cron",
"minLength": 1,
"title": "Trigger Type",
"type": "string"
},
"schedule": {
"minLength": 1,
"title": "Schedule",
"type": "string"
},
"timezone": {
"anyOf": [
{
"minLength": 1,
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Timezone"
},
"start_date": {
"anyOf": [
{
"format": "date-time",
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Start Date"
},
"end_date": {
"anyOf": [
{
"format": "date-time",
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "End Date"
}
},
"required": [
"repo",
"prompt",
"schedule"
],
"title": "CronAutomationConfiguration",
"type": "object"
}
Fields:
-
repo(NonEmptyString) -
path(Path | None) -
setup_script(str | None) -
checkout(Literal['worktree', 'main']) -
prompt(str) -
profile(Identifier | None) -
trigger_type(NonEmptyString) -
schedule(NonEmptyString) -
timezone(NonEmptyString | None) -
start_date(datetime | None) -
end_date(datetime | None)
Validators:
-
validate_setup_script→setup_script -
validate_repository→repo -
expand_path→path -
validate_prompt_syntax→prompt -
validate_schedule→schedule -
validate_optional_timezone→timezone
trigger_type = 'cron'
pydantic-field
schedule
pydantic-field
timezone = None
pydantic-field
start_date = None
pydantic-field
end_date = None
pydantic-field
model_config = ConfigDict(extra='forbid', frozen=True, validate_default=True)
class-attribute
instance-attribute
repo
pydantic-field
path = None
pydantic-field
setup_script = None
pydantic-field
checkout = 'worktree'
pydantic-field
prompt
pydantic-field
profile = None
pydantic-field
validate_schedule(value)
pydantic-validator
Require a valid five-field cron expression.
validate_optional_timezone(value)
pydantic-validator
Validate the optional IANA timezone.
validate_setup_script(value)
pydantic-validator
Require an optional repository-relative script path without traversal.
validate_repository(value)
pydantic-validator
Require the owner/repository format without traversal segments.
expand_path(value)
pydantic-validator
Expand the optional user-relative workspace override.
validate_prompt_syntax(value)
pydantic-validator
Reject empty prompts and invalid template placeholders.
CLI profiles
curupira.models.profiles.OpenCodeCliProfile
pydantic-model
Bases: CliProfileBase
OpenCode options, including native custom-agent selection.
Attributes:
| Name | Type | Description |
|---|---|---|
provider |
Literal['opencode']
|
Discriminator identifying the OpenCode CLI. |
agent |
NonEmptyString | None
|
Optional configured OpenCode agent name. |
effort |
NonEmptyString | None
|
Optional provider-specific effort level. |
auto_approve |
bool
|
Whether OpenCode runs with approval prompts disabled. |
Show JSON schema:
{
"additionalProperties": false,
"description": "OpenCode options, including native custom-agent selection.\n\nAttributes:\n provider: Discriminator identifying the OpenCode CLI.\n agent: Optional configured OpenCode agent name.\n effort: Optional provider-specific effort level.\n auto_approve: Whether OpenCode runs with approval prompts disabled.",
"properties": {
"model": {
"anyOf": [
{
"minLength": 1,
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Model"
},
"provider": {
"const": "opencode",
"default": "opencode",
"title": "Provider",
"type": "string"
},
"agent": {
"anyOf": [
{
"minLength": 1,
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Agent"
},
"effort": {
"anyOf": [
{
"minLength": 1,
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Effort"
},
"auto_approve": {
"default": false,
"title": "Auto Approve",
"type": "boolean"
}
},
"title": "OpenCodeCliProfile",
"type": "object"
}
Fields:
-
model(NonEmptyString | None) -
provider(Literal['opencode']) -
agent(NonEmptyString | None) -
effort(NonEmptyString | None) -
auto_approve(bool)
Validators:
provider = 'opencode'
pydantic-field
agent = None
pydantic-field
effort = None
pydantic-field
auto_approve = False
pydantic-field
model_config = ConfigDict(extra='forbid', frozen=True, validate_default=True)
class-attribute
instance-attribute
model = None
pydantic-field
validate_model_format()
pydantic-validator
Require the provider/model format.
curupira.models.profiles.CodexCliProfile
pydantic-model
Bases: CliProfileBase
Codex options, including selection of an existing CLI configuration profile.
Attributes:
| Name | Type | Description |
|---|---|---|
provider |
Literal['codex']
|
Discriminator identifying the Codex CLI. |
agent |
NonEmptyString | None
|
Optional configured Codex agent name. |
effort |
Literal['low', 'medium', 'high', 'xhigh', 'max', 'ultra'] | None
|
Optional Codex reasoning effort. |
sandbox |
Literal['read-only', 'workspace-write', 'danger-full-access'] | None
|
Optional Codex sandbox permission level. |
auto_review |
bool
|
Whether Codex should review changes automatically. |
Show JSON schema:
{
"additionalProperties": false,
"description": "Codex options, including selection of an existing CLI configuration profile.\n\nAttributes:\n provider: Discriminator identifying the Codex CLI.\n agent: Optional configured Codex agent name.\n effort: Optional Codex reasoning effort.\n sandbox: Optional Codex sandbox permission level.\n auto_review: Whether Codex should review changes automatically.",
"properties": {
"model": {
"anyOf": [
{
"minLength": 1,
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Model"
},
"provider": {
"const": "codex",
"default": "codex",
"title": "Provider",
"type": "string"
},
"agent": {
"anyOf": [
{
"minLength": 1,
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Agent"
},
"effort": {
"anyOf": [
{
"enum": [
"low",
"medium",
"high",
"xhigh",
"max",
"ultra"
],
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Effort"
},
"sandbox": {
"anyOf": [
{
"enum": [
"read-only",
"workspace-write",
"danger-full-access"
],
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Sandbox"
},
"auto_review": {
"default": false,
"title": "Auto Review",
"type": "boolean"
}
},
"title": "CodexCliProfile",
"type": "object"
}
Fields:
-
model(NonEmptyString | None) -
provider(Literal['codex']) -
agent(NonEmptyString | None) -
effort(Literal['low', 'medium', 'high', 'xhigh', 'max', 'ultra'] | None) -
sandbox(Literal['read-only', 'workspace-write', 'danger-full-access'] | None) -
auto_review(bool)
Validators:
provider = 'codex'
pydantic-field
agent = None
pydantic-field
effort = None
pydantic-field
sandbox = None
pydantic-field
auto_review = False
pydantic-field
model_config = ConfigDict(extra='forbid', frozen=True, validate_default=True)
class-attribute
instance-attribute
model = None
pydantic-field
validate_approval_options()
pydantic-validator
Require compatible Codex approval options.
curupira.models.profiles.ClaudeCodeCliProfile
pydantic-model
Bases: CliProfileBase
Claude Code options, including native custom-agent selection.
Attributes:
| Name | Type | Description |
|---|---|---|
provider |
Literal['claude']
|
Discriminator identifying the Claude Code CLI. |
agent |
NonEmptyString | None
|
Optional configured Claude Code agent name. |
effort |
Literal['low', 'medium', 'high', 'xhigh', 'max', 'ultracode'] | None
|
Optional Claude model effort level. |
permission_mode |
Literal['default', 'acceptEdits', 'plan', 'auto', 'dontAsk', 'bypassPermissions'] | None
|
Optional Claude Code permission mode. |
permission_prompts |
Literal['host', 'none'] | None
|
Whether permission prompts are handled by the host or disabled. |
Show JSON schema:
{
"additionalProperties": false,
"description": "Claude Code options, including native custom-agent selection.\n\nAttributes:\n provider: Discriminator identifying the Claude Code CLI.\n agent: Optional configured Claude Code agent name.\n effort: Optional Claude model effort level.\n permission_mode: Optional Claude Code permission mode.\n permission_prompts: Whether permission prompts are handled by the host or disabled.",
"properties": {
"model": {
"anyOf": [
{
"minLength": 1,
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Model"
},
"provider": {
"const": "claude",
"default": "claude",
"title": "Provider",
"type": "string"
},
"agent": {
"anyOf": [
{
"minLength": 1,
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Agent"
},
"effort": {
"anyOf": [
{
"enum": [
"low",
"medium",
"high",
"xhigh",
"max",
"ultracode"
],
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Effort"
},
"permission_mode": {
"anyOf": [
{
"enum": [
"default",
"acceptEdits",
"plan",
"auto",
"dontAsk",
"bypassPermissions"
],
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Permission Mode"
},
"permission_prompts": {
"anyOf": [
{
"enum": [
"host",
"none"
],
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Permission Prompts"
}
},
"title": "ClaudeCodeCliProfile",
"type": "object"
}
Fields:
-
model(NonEmptyString | None) -
provider(Literal['claude']) -
agent(NonEmptyString | None) -
effort(Literal['low', 'medium', 'high', 'xhigh', 'max', 'ultracode'] | None) -
permission_mode(Literal['default', 'acceptEdits', 'plan', 'auto', 'dontAsk', 'bypassPermissions'] | None) -
permission_prompts(Literal['host', 'none'] | None)
provider = 'claude'
pydantic-field
agent = None
pydantic-field
effort = None
pydantic-field
permission_mode = None
pydantic-field
permission_prompts = None
pydantic-field
model_config = ConfigDict(extra='forbid', frozen=True, validate_default=True)
class-attribute
instance-attribute
model = None
pydantic-field
curupira.models.profiles.CursorCliProfile
pydantic-model
Bases: CliProfileBase
Cursor options, including native agent/ask/plan mode selection.
Attributes:
| Name | Type | Description |
|---|---|---|
provider |
Literal['cursor']
|
Discriminator identifying the Cursor CLI. |
agent |
Literal['agent', 'ask', 'plan'] | None
|
Optional Cursor execution mode. |
force |
bool
|
Whether to force execution in a non-interactive environment. |
trust |
bool
|
Whether to trust the current workspace. |
Show JSON schema:
{
"additionalProperties": false,
"description": "Cursor options, including native agent/ask/plan mode selection.\n\nAttributes:\n provider: Discriminator identifying the Cursor CLI.\n agent: Optional Cursor execution mode.\n force: Whether to force execution in a non-interactive environment.\n trust: Whether to trust the current workspace.",
"properties": {
"model": {
"anyOf": [
{
"minLength": 1,
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Model"
},
"provider": {
"const": "cursor",
"default": "cursor",
"title": "Provider",
"type": "string"
},
"agent": {
"anyOf": [
{
"enum": [
"agent",
"ask",
"plan"
],
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Agent"
},
"force": {
"default": false,
"title": "Force",
"type": "boolean"
},
"trust": {
"default": false,
"title": "Trust",
"type": "boolean"
}
},
"title": "CursorCliProfile",
"type": "object"
}
Fields:
-
model(NonEmptyString | None) -
provider(Literal['cursor']) -
agent(Literal['agent', 'ask', 'plan'] | None) -
force(bool) -
trust(bool)
provider = 'cursor'
pydantic-field
agent = None
pydantic-field
force = False
pydantic-field
trust = False
pydantic-field
model_config = ConfigDict(extra='forbid', frozen=True, validate_default=True)
class-attribute
instance-attribute
model = None
pydantic-field
One TOML file contains global limits, coding-agent profiles, and automations. An automation watches issues, pull requests, or a cron schedule.
[settings]
max_active_tasks = 1
workspace_dir = "~/.curupira/workspaces"
state_db_path = "~/.curupira/state.sqlite3"
[settings.polling]
poll_interval_seconds = 30
batch_size = 100
cron_poll_interval_seconds = 1
[coding_agents.defaults]
profile = "opencode-default"
timezone = "UTC"
[coding_agents.profiles.opencode-default]
provider = "opencode"
[coding_agents.automations.resolve-ready-issues]
trigger_type = "issue"
repo = "acme/api"
query = "is:open label:agent-ready sort:created-asc"
prompt = "Resolve issue ${issue_number}: ${issue_title}\n\n${issue_body}"
Save this as ~/.curupira/settings.toml. The keys under profiles and automations are user-chosen identifiers; profile connects an automation to an existing profile.
Automations
trigger_type selects the source:
issuediscovers matching issues using GitHub Search syntax inquery.pull_requestdiscovers matching pull requests usingquery.cronproduces occurrences from a five-fieldscheduleinstead of querying GitHub.
Each automation requires repo, prompt, and either query or schedule. Optional profile selects a CLI profile. Optional path pins the automation to an existing checkout or an alternative clone destination. Relative paths are resolved from the TOML file's directory. Different repositories cannot share one workspace path. Automations keep file order, and one-shot selection follows that order.
Placeholders use ${name} syntax and are validated when the configuration loads. Common placeholders include ${repo}, ${automation_id}, ${task_type}, ${task_number}, ${task_title}, ${task_body}, and ${task_url}. Issues and pull requests provide their respective number, title, body, and URL placeholders; pull requests also provide ${pull_request_is_draft}, ${pull_request_head_ref}, and ${pull_request_base_ref}. For cron tasks, ${task_number} is the occurrence timestamp.
Checkout and setup
Each task uses its own worktree by default, created from the fetched remote default branch. Set checkout = "main" to use the shared checkout as-is; OpsCli does not fetch, pull, or switch branches in that mode. path continues to select the base checkout.
setup_script is a repository-relative executable path with no absolute path or ... It runs directly only after a base checkout is freshly cloned, not for an existing checkout or in a task worktree. A nonzero exit prevents the agent from starting and removes the newly cloned checkout. Validation checks path syntax but does not require the script to exist. run --dry-run does not fetch, clone, create worktrees, or run setup.
Scheduling and state
Polls fetch up to batch_size items (default 100, maximum 1000). Empty poll cycles back off from poll_interval_seconds (default 30 seconds) up to five minutes; discovery resets the wait. Automations deduplicate independently. Project queries keep the open state and filter board items to Todo.
max_active_tasks bounds concurrent agents. Checkouts using the same path run sequentially. Cron automations coalesce overdue ticks into one pending occurrence and never run themselves concurrently. schedule uses five cron fields; timezone is an IANA zone (default UTC), and optional start_date/end_date define an inclusive window. Without start_date, the window starts when the automation is first recorded.
State is stored in state_db_path (default ~/.curupira/state.sqlite3), the dispatch lock in ~/.curupira/dispatch.lock, and logs in ~/.curupira/logs. An incompatible database causes an error rather than automatic deletion. Only one run, batch, or watch process may dispatch at a time.
Telemetry
Set settings.otlp_endpoint to an OTLP/HTTP trace endpoint (for example, http://localhost:4318/v1/traces) to export one span per dispatched task. If omitted, no telemetry is exported.