Skip to content

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:

Validators:

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 = 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:

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:

Validators:

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:

Validators:

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:

Validators:

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:

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:

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:

  • issue discovers matching issues using GitHub Search syntax in query.
  • pull_request discovers matching pull requests using query.
  • cron produces occurrences from a five-field schedule instead 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.