9.2 KiB
Investigation and plan: Ticket config role profile mapping
Conclusion
Implement .yoi/ticket.config.toml as Ticket orchestration configuration with fixed Ticket role slots. Do not build a generic Role registry.
The initial implementation should parse/validate the config, provide defaults, expose role-to-profile and prompt/workflow references, and wire the configured backend root into the existing Ticket built-in feature adapter. Pod spawning, TUI actions, and workflow state should remain follow-up work.
Design position
Use fixed Ticket roles:
intakeorchestratorcoderreviewerinvestigator
These are not arbitrary user-defined roles. They are the roles required by the Ticket feature/workflows.
Keep the boundary:
- Profile: Pod runtime recipe.
- Ticket role config: binds a fixed Ticket role to a Profile selector and optional prompt/workflow refs.
- System instruction: role's durable behavior/boundary.
- Launch prompt: first committed task/user message for a concrete Ticket/action.
- Workflow: procedural flow, later possibly stateful.
Current code map
Ticket backend/tools
crates/ticket/src/lib.rs- Owns Ticket domain/backend and
LocalTicketBackend. - Current backend root is supplied by callers.
- Owns Ticket domain/backend and
crates/ticket/src/tool.rs- Owns Ticket tool input/output and
llm_worker::Toolimplementations.
- Owns Ticket tool input/output and
crates/pod/src/feature/builtin/ticket.rs- Thin built-in feature adapter.
- Currently resolves
<workspace>/work-itemsdirectly. - This is the first integration point for
.yoi/ticket.config.tomlbackend root.
Feature/host authority
crates/pod/src/feature.rs- Defines
HostAuthority::TicketBackend { root }. - Feature descriptor/install path already supports requested host authority and tool contribution wiring.
- Defines
Profile selection
crates/manifest/src/profile.rs- Owns Profile registry/selector resolution.
SpawnPod.profilealready accepts selectors such asinherit, default/source-qualified/unambiguous registry names.
crates/pod/src/spawn/tool.rs- Implements
SpawnPodtool input with optional profile selector andinheritsemantics. - This should remain the actual spawning boundary; config should not duplicate full profile resolution behavior.
- Implements
Workflow resources
.yoi/workflow/*.md- Current workflow files are project-authored resources.
ticket-intake-workflow.md,ticket-orchestrator-routing.md,ticket-preflight-workflow.md, andmulti-agent-workflow.mdare the relevant workflow refs.
crates/workflow/src/workflow.rs- Parses workflow frontmatter/body records.
- No stateful workflow runner exists yet.
Prompt resources / system instruction
crates/pod/src/prompt/loader.rs- Resolves instruction-file references like
$yoi/...and$user/...for current startup/instruction use.
- Resolves instruction-file references like
- Prompt catalog/resources are currently separate from workflow state.
- There is no implemented role-specific launch prompt engine yet.
Important constraint
Do not make ticket depend on pod.
Possible dependency choices:
-
Put config parsing in
ticketcrate with raw profile/prompt/workflow string refs.- Pros: Ticket config is close to Ticket backend concept.
- Cons:
ticketlearns about profile/prompt/workflow reference strings, but not their runtime resolution.
-
Put config parsing in
pod.- Pros: avoids exposing prompt/profile concepts from
ticket. - Cons: Ticket config becomes less reusable by future CLI/TUI code unless those crates also depend on
pod.
- Pros: avoids exposing prompt/profile concepts from
Recommended MVP:
- Add config domain/parser to
crates/ticket, using lightweight string wrapper types such asProfileSelectorRef,PromptRef, andWorkflowRefwithout depending onmanifestorpod. podconsumes this config and performs runtime interpretation where needed.
This preserves:
ticket -> llm-worker / serde / toml only
pod -> ticket
and avoids:
ticket -> pod
Proposed schema
[backend]
kind = "local"
root = "work-items"
[roles.intake]
profile = "project:intake"
system_instruction = "$workspace/ticket/intake/system"
launch_prompt = "$workspace/ticket/intake/launch"
workflow = "ticket-intake-workflow"
[roles.orchestrator]
profile = "project:orchestrator"
system_instruction = "$workspace/ticket/orchestrator/system"
launch_prompt = "$workspace/ticket/orchestrator/launch"
workflow = "ticket-orchestrator-routing"
[roles.coder]
profile = "inherit"
system_instruction = "$workspace/ticket/coder/system"
launch_prompt = "$workspace/ticket/coder/launch"
workflow = "multi-agent-workflow"
[roles.reviewer]
profile = "project:reviewer"
system_instruction = "$workspace/ticket/reviewer/system"
launch_prompt = "$workspace/ticket/reviewer/launch"
workflow = "multi-agent-workflow"
[roles.investigator]
profile = "inherit"
system_instruction = "$workspace/ticket/investigator/system"
launch_prompt = "$workspace/ticket/investigator/launch"
workflow = "ticket-orchestrator-routing"
The specific prompt ref syntax should be accepted as opaque strings in this ticket. Runtime prompt resolution belongs to the later role launcher.
Defaults
When .yoi/ticket.config.toml is missing:
- backend kind:
local - backend root:
work-items - role profiles:
inherit - workflow defaults:
- intake:
ticket-intake-workflow - orchestrator:
ticket-orchestrator-routing - coder:
multi-agent-workflow - reviewer:
multi-agent-workflow - investigator:
ticket-orchestrator-routing
- intake:
- system instruction / launch prompt: none
When a role section exists but omits optional prompt/workflow refs:
- keep configured profile;
- fill workflow default for the fixed role;
- leave prompt refs as none.
Implementation plan
Phase 1: Config model/parser in ticket
Add a module such as crates/ticket/src/config.rs.
Types:
pub struct TicketConfig {
pub backend: TicketBackendConfig,
pub roles: TicketRoleProfiles,
}
pub struct TicketBackendConfig {
pub kind: TicketBackendKind,
pub root: PathBuf,
}
pub enum TicketBackendKind {
Local,
}
pub enum TicketRole {
Intake,
Orchestrator,
Coder,
Reviewer,
Investigator,
}
pub struct TicketRoleProfile {
pub profile: ProfileSelectorRef,
pub system_instruction: Option<PromptRef>,
pub launch_prompt: Option<PromptRef>,
pub workflow: WorkflowRef,
}
Use string wrapper types for selectors/refs to avoid depending on manifest/pod.
Parsing behavior:
TicketConfig::load_workspace(workspace_root: &Path)reads.yoi/ticket.config.tomlif present.- Missing file returns defaults.
- Relative backend root resolves against workspace root.
- Unknown roles are errors.
- Unknown top-level fields should be diagnostics/errors rather than silently ignored.
- Backend kind supports only
localfor now.
Phase 2: Wire backend root into Pod Ticket feature adapter
Update crates/pod/src/feature/builtin/ticket.rs:
- Load
TicketConfigfrom workspace root. - Use
config.backend.rootinstead of hard-codedworkspace/work-items. - Preserve current fail-closed behavior if root is missing/unusable.
- Keep
HostAuthority::TicketBackend { root }consistent with the validated/canonical root where practical.
This directly improves existing Ticket tools without introducing role spawning yet.
Phase 3: Tests
Ticket crate tests:
- missing config -> defaults;
- full config parses;
- partial role config uses role workflow defaults;
- unknown role rejects;
- unsupported backend kind rejects;
- relative backend root resolves against workspace;
- malformed profile/ref diagnostics are bounded.
Pod tests:
- Ticket built-in feature uses configured backend root;
- missing/unusable configured backend root does not register tools;
- default missing config still uses
<workspace>/work-items.
Phase 4: Documentation/example
Add one of:
- a short
.yoi/ticket.config.example.toml, or - a documented snippet under the ticket implementation report / docs if adding tracked config now is too early.
For this repository, adding actual .yoi/ticket.config.toml should be considered carefully. If added, defaults should likely use inherit profiles until dedicated profiles exist.
Deferred follow-ups
ticket-role-pod-launcher
- Take TicketRole + Ticket context + role config.
- Build
SpawnPodrequests. - Resolve profile selector using existing Profile registry.
- Resolve role system instruction separately from initial launch prompt.
- Commit launch prompt as the first user/task message, not hidden context.
- Include workflow ref in launch/task context.
tui-ticket-role-actions
- Add TUI actions for fixed Ticket roles:
- Intake/refine Ticket;
- Route Ticket;
- Investigate;
- Implement;
- Review.
- Use the launcher rather than building SpawnPod requests inside UI code.
Stateful workflow engine
- Persist workflow phase/state.
- Gate allowed tools by phase.
- Inject phase prompts only by committing them to history first.
- Keep SystemInstruction role-stable and task/phase prompts dynamic.
Validation for implementation
Required:
cargo test -p ticketcargo test -p pod ticket --libcargo test -p pod feature --libcargo check --workspace --all-targetscargo fmt --checkgit diff --check./tickets.sh doctor
Optional if feasible:
nix build .#yoi --no-link