project
project
¶
Rich Project domain object — DDD Aggregate Root.
The central domain object in terok's architecture. Project wraps a
ProjectConfig value object with
lifecycle behavior and serves as the single entry point for all
project-scoped operations:
- Task management — create, list, run, and stop tasks
(
project.create_task(),project.list_tasks(status="running")) - Security setup — SSH keypairs (
project.ssh) and git gate mirrors (project.gate) - Agent configuration — layered config resolution and provider selection
(
project.agents) - Infrastructure — Dockerfile generation, image builds, and state queries
The object graph follows DDD conventions::
get_project("myproj") → Project (Aggregate Root)
.config → ProjectConfig (Value Object)
.gate → GitGate (Repository + Gateway)
.ssh → SSHManager (Service)
.agents → AgentManager (Strategy + Config Stack)
.create_task() → Task (Entity)
.get_task(id) → Task (Entity)
Subsystems (gate, ssh, agents) are lazy-initialized on first
access — constructing a Project performs no I/O beyond loading the
config that was already resolved by the caller.
This module also contains delete_project and its helpers, which
handle the full teardown of a project including archiving, task cleanup,
and safe removal of managed directories.
See Also
get_project — factory that returns a rich Project
terok.lib.domain.task — the Task entity contained by Project
terok.lib.core.project_model — the ProjectConfig value object
DeleteProjectResult
¶
ACPEndpoint(project_name, task_id, socket_path, status, bound_agent=None)
dataclass
¶
One per-task ACP endpoint as visible from the host.
Constructed by acp_endpoints; consumed by the CLI
(terok acp list) and the TUI panel. Carries enough state to
render a status row without forcing the listing path to actually
probe or open the socket.
project_name
instance-attribute
¶
The owning project's name.
task_id
instance-attribute
¶
The task this endpoint serves.
socket_path
instance-attribute
¶
Where the proxy daemon would bind (or has bound) the socket.
The path is computed deterministically from the task id and may not
yet exist on disk — status records whether it does.
status
instance-attribute
¶
Live state — active, ready, or unsupported.
bound_agent = None
class-attribute
instance-attribute
¶
Set only when status == ACTIVE and the daemon has bound an
agent for the open session; None otherwise.
AgentManager(config)
¶
Project-scoped agent configuration manager (Strategy + Config Stack).
Resolves the layered agent configuration stack (global → project → CLI
overrides) and selects the active headless provider for a
project. Used by Project via project.agents.
The config stack is resolved lazily on each call — the manager holds no cached state, so config file changes take effect immediately.
Initialize with a resolved project configuration.
Source code in src/terok/lib/domain/project.py
__slots__ = ('_config',)
class-attribute
instance-attribute
¶
resolve_config(cli_overrides=None)
¶
Return the merged agent config dict.
Source code in src/terok/lib/domain/project.py
resolve_instructions(provider_name)
¶
Return resolved instructions text for the given provider.
Source code in src/terok/lib/domain/project.py
get_agent(name=None)
¶
Project(config)
¶
Rich project object — DDD Aggregate Root.
The primary domain object that callers interact with. Wraps a
ProjectConfig value object and exposes all project-scoped
operations through a natural OOP interface::
project = get_project("myproj")
task = project.create_task(name="fix-bug")
task.run_cli()
task.stop()
project.gate.sync()
Identity is based on project.name — two Project instances with
the same name compare equal and hash identically, so they work correctly
in sets and dicts.
Subsystem access (gate, ssh, agents) uses lazy
initialization: the service objects are created on first property access
rather than at construction time. This avoids unnecessary I/O when only
a subset of functionality is needed. Uses __slots__ for memory
efficiency; cached_property is not available because it requires
__dict__.
Obtain via get_project or
list_projects.
Initialize with a resolved project configuration.
Source code in src/terok/lib/domain/project.py
__slots__ = ('_config', '_gate', '_ssh', '_agents')
class-attribute
instance-attribute
¶
name
property
¶
Return the project name (slug).
config
property
¶
Return the underlying configuration value object.
security_class
property
¶
Return the project's security class ('online' or 'gatekeeping').
tasks
property
¶
All tasks in this project — convenience for unfiltered iteration.
gate
property
¶
Return the project-scoped git gate manager (lazy-initialized).
ssh
property
¶
Return the project-scoped SSH manager (lazy-initialized).
needs_ssh_key_registration
property
¶
Return True when the upstream is SSH-scheme so a deploy key must be added.
Shared predicate used by the CLI pause helper and the TUI wizard's mid-flow "continue" gate — keeps the rule (SSH URLs need registration, HTTPS and no-upstream projects don't) in one place.
agents
property
¶
Return the project-scoped agent configuration manager (lazy-initialized).
__eq__(other)
¶
__hash__()
¶
create_task(*, name=None)
¶
Create a new task and return a rich Task entity.
Source code in src/terok/lib/domain/project.py
get_task(task_id)
¶
list_tasks(*, status=None, mode=None)
¶
Return all tasks, optionally filtered by status or mode.
Source code in src/terok/lib/domain/project.py
acp_endpoints()
¶
Return one ACPEndpoint per running task.
Cheap discovery surface — walks running tasks, classifies each
endpoint as active (daemon up, socket bound), ready
(task running with at least one authed agent, daemon would
spawn on first connect), or unsupported (no agents authed
for this task's image; connect would fail).
No probing, no socket traffic — one credential-DB read for
the whole listing, one Sandbox instance shared across
tasks, and image-label lookups memoised by image-id (most
tasks share an image). terok acp list and the TUI panel
share this entry point.
Source code in src/terok/lib/domain/project.py
run_headless(request)
¶
Create and run a headless task atomically. Returns the Task.
Source code in src/terok/lib/domain/project.py
followup_headless(task_id, prompt, follow=True)
¶
Send a follow-up prompt to a completed headless task.
Source code in src/terok/lib/domain/project.py
delete()
¶
generate_dockerfiles()
¶
build_images(*, include_dev=False, refresh_agents=False, full=False)
¶
Build container images for this project.
Source code in src/terok/lib/domain/project.py
state(*, gate_commit_provider=None, gate_pending_provider=None)
¶
Return the project's infrastructure state snapshot.
gate_commit_provider is an optional callable that, given a
project name, returns the last gate commit dict (or None).
Used by the TUI to inject the live gate manager's last_commit
lookup without reaching for it from inside the helper.
gate_pending_provider does the same for the count of pending
destructive gate ops (the TUI's pending! badge).
Source code in src/terok/lib/domain/project.py
storage_detail()
¶
Return a detailed view of this project's on-disk footprint.
suggested_ssh_key_comment(*, force=False, prompt_on_tty=False)
¶
Suggest a new key's comment, or None when init would reuse a key.
CLI callers may enable the vault's TTY unlock prompt; TUI callers keep it disabled so a locked vault cannot block on terminal input.
Source code in src/terok/lib/domain/project.py
provision_ssh_key(*, key_type='ed25519', comment=None, force=False)
¶
Mint a vault-backed keypair and bind it to this project's scope.
Opens a fresh
SSHManager via the context-manager
form so the credential DB closes after init, then assigns the
new key_id to the project scope. Rendering the result is
the caller's job — see
summarize_ssh_init.
Source code in src/terok/lib/domain/project.py
register_ssh_key(key_id)
¶
Bind an already-minted key_id to this project (idempotent).
pause_for_ssh_key_registration_if_needed()
¶
Pause so the user can register the deploy key — only for SSH upstreams.
Source code in src/terok/lib/domain/project.py
find_projects_sharing_gate(gate_path, exclude_project=None)
¶
Find all projects configured to use the same gate path.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
gate_path
|
Path
|
The gate path to check for |
required |
exclude_project
|
str | None
|
Project name to exclude from results (usually the current project) |
None
|
Returns:
| Type | Description |
|---|---|
list[tuple[str, str | None]]
|
List of (project_name, upstream_url) tuples for projects sharing this gate |
Source code in src/terok/lib/domain/project.py
validate_gate_upstream_match(project_name)
¶
Validate that no other project uses the same gate with a different upstream.
Raises SystemExit if another project uses the same gate path but has a different upstream_url configured.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
project_name
|
str
|
The project to validate |
required |
Source code in src/terok/lib/domain/project.py
make_git_gate(config, *, use_personal_ssh=None)
¶
Construct a GitGate from a ProjectConfig (adapter factory).
Injects validate_gate_upstream_match as the gate validation callback.
The use_personal_ssh flag resolves per-invocation override (e.g.
terok gate-sync --use-personal-ssh) > per-project YAML
(ssh.use_personal) > default False.
Source code in src/terok/lib/domain/project.py
describe_pending_op(op)
¶
Render one pending destructive gate op as a single decision-ready line.
The operator confirms these sight-unseen otherwise — the line must carry the branch, what would happen, why, and above all whether any gate-local (agent) commits would be discarded.
Source code in src/terok/lib/domain/project.py
summarize_gate_sync(result)
¶
Turn a gate sync report into the abridged lines the CLI/TUI print.
Shows what actually happened branch by branch — the whole point of the structured report — while capping each category so a first sync of a thousand-branch repo doesn't scroll the terminal into oblivion.
Source code in src/terok/lib/domain/project.py
make_ssh_manager(config)
¶
Return an SSHManager for config that owns its vault DB.
Use it as a context manager (with make_ssh_manager(cfg) as m: ...);
the DB connection closes on exit.
Source code in src/terok/lib/domain/project.py
project_image_exists(project_name)
¶
Return True when the project's L2 CLI image is present locally.
list_projects()
¶
derive_project(source_id, new_id)
¶
Copy source_id's gate mirror and vault SSH assignments under new_id.
Source code in src/terok/lib/domain/project.py
delete_project(project_name)
¶
Delete a project and all its associated data.
Removes task workspaces, task metadata, build artifacts, SSH credentials, the git gate (if not shared with other projects), and the project config directory.