Skip to content

Meta

Meta-orchestration subsystems: charter interviews, governance, and the conversational organisation interface. The charter subsystem (which produces a project charter from a deep interview) is documented below; other meta surfaces are internal wiring.

Charter Enums

enums

Charter domain enumerations.

CharterStatus

Bases: StrEnum

Lifecycle state of a project charter produced by a deep interview.

Attributes:

Name Type Description
DRAFTED

The interview produced a charter draft; the user may review and edit it in place. The only non-terminal state.

APPROVED

The charter was approved and dispatched into the work pipeline spine as a real project run. Terminal.

CANCELLED

The charter was discarded before approval. Terminal.

Charter Models

models

Domain models for the deep CEO interview to project charter flow.

A vague one-line product idea is turned, through a structured requirements-elicitation interview, into a single :class:ProjectCharter artifact the user reviews, edits, and approves. On approval the charter becomes the authoritative input that drives a real project run through the work pipeline spine.

The interview reuses the Chief of Staff conversation substrate (Conversation + ConversationTurn); these models cover only the charter artifact, the structured interview decision, and the service and controller boundary args.

BudgetEnvelope pydantic-model

Bases: BaseModel

The budget and time envelope elicited during the interview.

Attributes:

Name Type Description
amount float

Total budget ceiling for the project run, in currency. Stamped as the run hard ceiling on approval.

currency CurrencyCode

ISO 4217 code; must match the live budget.currency setting at approval time (enforced by the dispatcher).

deadline AwareDatetime | None

Optional hard deadline for the project.

time_horizon NotBlankStr | None

Optional free-text horizon (e.g. "2 weeks") when an absolute deadline is not yet known.

Config:

  • frozen: True
  • allow_inf_nan: False
  • extra: forbid

Fields:

amount pydantic-field

amount

Budget ceiling in currency

currency pydantic-field

currency

ISO 4217 currency code

ScopeBoundaries pydantic-model

Bases: BaseModel

Explicit in-scope and out-of-scope statements for the project.

Attributes:

Name Type Description
in_scope tuple[NotBlankStr, ...]

Capabilities/outcomes the project commits to deliver.

out_of_scope tuple[NotBlankStr, ...]

Capabilities/outcomes deliberately excluded.

Config:

  • frozen: True
  • allow_inf_nan: False
  • extra: forbid

Fields:

CharterDraft pydantic-model

Bases: BaseModel

The structured charter the interview strategy emits.

Carries content + project binding + envelope only; lifecycle and dispatch provenance are added by the service when it mints the persisted :class:ProjectCharter.

Attributes:

Name Type Description
title NotBlankStr

Short human-readable charter title.

brief NotBlankStr

The elaborated goal statement / project brief.

goals tuple[NotBlankStr, ...]

Concrete goals the project pursues.

constraints tuple[NotBlankStr, ...]

Constraints the work must respect.

success_criteria tuple[NotBlankStr, ...]

Measurable criteria for project success; become the task acceptance criteria on approval.

scope ScopeBoundaries

Explicit in/out scope boundaries.

envelope BudgetEnvelope

Budget and time envelope.

project_id NotBlankStr | None

Existing project to file the run under (XOR).

proposed_project_name NotBlankStr | None

Name of a new project to create (XOR).

proposed_project_description str

Description for the new project.

Config:

  • frozen: True
  • allow_inf_nan: False
  • extra: forbid

Fields:

Validators:

  • _validate_binding

InterviewDecision pydantic-model

Bases: BaseModel

Structured output of one interview model turn.

Exactly one branch is taken: either the interviewer asks a single elicitation question, or it emits a complete charter draft. The strategy self-asserts coverage (goals, constraints, success criteria, scope, envelope all populated) by emitting draft instead of next_question.

Attributes:

Name Type Description
needs_more bool

True while requirements are still being elicited.

next_question NotBlankStr | None

The question to put to the user; required iff needs_more.

draft CharterDraft | None

The completed charter draft; set iff not needs_more.

Config:

  • frozen: True
  • allow_inf_nan: False
  • extra: forbid

Fields:

Validators:

  • _validate_exclusive_branch

ProjectCharter pydantic-model

Bases: BaseModel

The reviewable, approvable project charter artifact.

Persisted via CharterRepository. Created in DRAFTED when the interview converges, edited in place during review, and transitioned to APPROVED (dispatched to the spine) or CANCELLED.

Attributes:

Name Type Description
id NotBlankStr

Unique charter identifier.

conversation_id NotBlankStr

Originating interview conversation id.

created_by NotBlankStr

User id that ran the interview.

version int

Monotonic edit version (starts at 1).

status CharterStatus

Lifecycle state.

project_id / proposed_project_name / proposed_project_description

Project binding (existing-vs-new XOR).

created_at, updated_at

Row timestamps.

approved_at, approved_by

Set iff status is APPROVED.

forecast_id, (correlation_id, task_id)

Dispatch provenance set on approval; None otherwise.

Config:

  • frozen: True
  • allow_inf_nan: False
  • extra: forbid

Fields:

Validators:

  • _validate_binding
  • _validate_approval_coupling

InterviewTurnArgs pydantic-model

Bases: BaseModel

Args for one :meth:CharterInterviewService.run_turn turn.

Attributes:

Name Type Description
message NotBlankStr

The user's natural-language message this turn.

created_by NotBlankStr

User id that owns the conversation.

conversation_id NotBlankStr | None

Existing conversation to continue, or None to open a new interview.

project NotBlankStr | None

Optional existing project id the run should target; used as a hint when the interview drafts the charter.

Config:

  • frozen: True
  • allow_inf_nan: False
  • extra: forbid

Fields:

CharterEditArgs pydantic-model

Bases: BaseModel

Args for an in-place charter edit during review.

Every field is optional; only provided fields are updated (replace semantics, None skips). status is never editable here -- approval and cancellation have dedicated transitions.

Config:

  • frozen: True
  • allow_inf_nan: False
  • extra: forbid

Fields:

InterviewTurnResult pydantic-model

Bases: BaseModel

Outcome of one interview turn.

Exactly one branch: an elicitation question (conversation stays open) or a drafted charter (conversation moves to PROPOSED).

Attributes:

Name Type Description
conversation_id NotBlankStr

The conversation this turn belongs to.

status Literal['needs_more', 'drafted']

"needs_more" or "drafted".

next_question NotBlankStr | None

Set iff status == "needs_more".

charter ProjectCharter | None

The drafted charter; set iff status == "drafted".

conversation_closed bool

True when the interview turn cap was reached and the conversation was force-closed.

Config:

  • frozen: True
  • allow_inf_nan: False
  • extra: forbid

Fields:

Validators:

  • _validate_status_payload

CharterApprovalResult pydantic-model

Bases: BaseModel

Outcome of approving a charter and dispatching the project run.

Attributes:

Name Type Description
charter ProjectCharter

The approved charter (with dispatch provenance stamped).

project_id NotBlankStr

The project the run was filed under.

task_id NotBlankStr

The spine-created task id.

is_success bool

Whether the pipeline run reported success.

Config:

  • frozen: True
  • allow_inf_nan: False
  • extra: forbid

Fields:

Charter Service

service

Deep CEO interview to project charter orchestration service.

Drives a multi-turn requirements-elicitation interview over the Chief of Staff conversation substrate (Conversation + ConversationTurn) and produces a single reviewable :class:ProjectCharter per conversation. Each turn either records an elicitation question or persists / updates the charter draft. Nothing executes here: an approved charter is dispatched into the work pipeline by CharterDispatcher via the dedicated approve endpoint.

CharterInterviewService

CharterInterviewService(
    *, strategy, config, conversation_repo, turn_repo, charter_repo, clock=None
)

Bases: CharterCrudMixin

Multi-turn charter interview orchestrator.

Parameters:

Name Type Description Default
strategy CharterInterviewStrategy

Pluggable interview strategy (one model turn).

required
config CharterConfig

Charter-interview configuration.

required
conversation_repo ConversationRepository

Conversation header store.

required
turn_repo ConversationTurnRepository

Append-only conversation turn store.

required
charter_repo CharterRepository

Project charter store.

required
clock Clock | None

Injectable time source (defaults to SystemClock).

None
Source code in src/synthorg/meta/charter/service.py
def __init__(  # noqa: PLR0913 -- DI seam: independently-wired collaborators
    self,
    *,
    strategy: CharterInterviewStrategy,
    config: CharterConfig,
    conversation_repo: ConversationRepository,
    turn_repo: ConversationTurnRepository,
    charter_repo: CharterRepository,
    clock: Clock | None = None,
) -> None:
    self._strategy = strategy
    self._config = config
    self._conversation_repo = conversation_repo
    self._turn_repo = turn_repo
    self._charter_repo = charter_repo
    self._clock: Clock = clock or SystemClock()
    # Per-conversation locks serialise the turn pipeline so two
    # concurrent run_turn() calls on one conversation cannot
    # interleave their history snapshots nor double-create charters.
    # Lazy-initialised so the guard binds to the request loop.
    self._conversation_locks: dict[str, asyncio.Lock] = {}
    self._conversation_locks_guard: asyncio.Lock | None = None

run_turn async

run_turn(args)

Run one interview turn (elicit a question or draft the charter).

Raises:

Type Description
ConversationNotFoundError

conversation_id is unknown.

ConversationClosedError

The conversation is terminal.

CharterInterviewResponseInvalidError

The model output did not satisfy the structured contract.

Returns:

Type Description
InterviewTurnResult

InterviewTurnResult instance.

Source code in src/synthorg/meta/charter/service.py
async def run_turn(self, args: InterviewTurnArgs) -> InterviewTurnResult:
    """Run one interview turn (elicit a question or draft the charter).

    Raises:
        ConversationNotFoundError: ``conversation_id`` is unknown.
        ConversationClosedError: The conversation is terminal.
        CharterInterviewResponseInvalidError: The model output did
            not satisfy the structured contract.

    Returns:
        ``InterviewTurnResult`` instance.
    """
    now = self._clock.now()
    conversation = await self._resolve_conversation(args, now)
    async with await self._lock_for(conversation.id):
        return await self._run_turn(conversation, args, now)