Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,37 @@ The package installs the local data directory at `~/.hasna/tai/`.
```bash
tai propose "show the largest files in this repo"
tai plan "inspect the repo status, run the relevant checks, and show me the safe next commands"
tai agents
tai agents --json
tai agents show todos:<task-uuid>
tai classify "rm -rf dist"
tai run "ls -la" --yes
```

`tai run` streams stdout/stderr directly and exits with the child command status. It preserves the current working directory and environment by default, and forwards common process signals to the child.

### Headless agent visibility

`tai agents [--limit <1-200>]` is a stateless, read-only projection of independently safe provider surfaces. The default output limit is 50. `tai agents show <provider>:<safe-run-id>` performs an exact lookup against only the selected provider. Add `--json` to either form for the versioned machine contract. `--limit` is rejected for exact lookup.

TAI does not invoke the installed `codewith agent list`, `claude agents`, or `todos active` routes: those routes can create configuration or database files, change permissions, or clean expired locks. It also does not call the authenticated Todos `/v1` GET surface because the provider initializes database schema before request dispatch. Codewith, Claude, and exact Todos therefore report `side-effect-free-surface-unavailable` until those providers expose a demonstrably side-effect-free structured read API. Todos list reports `side-effect-free-source-limit-unavailable`: its task-list implementation cleans expired locks, while its agent-list API has no authoritative source limit.

No current provider surface satisfies the full read-only proof, so `tai agents` returns a structured unavailable envelope and nonzero exit without consulting provider configuration, credentials, HTTP endpoints, or local state. Exact show still selects only the encoded provider, but an unsupported source returns `agent-lookup-incomplete` without performing an operation. Configuration such as `TODOS_URL`, including loopback URLs, does not enable Todos visibility.

Missing providers fail soft while any independently safe source responds. If every source is unavailable or errors, the command exits nonzero. Exact lookup may return `agent-not-found` only after a future safe provider surface proves structured, canonical absence; HTTP status, HTML, redirects, partial responses, malformed bodies, unavailable, truncated, or otherwise unproven evidence remains `agent-lookup-incomplete`. A future Todos projection must follow authoritative provider lease ownership and expiry semantics; assignment, task status, or a printable `agent_id` alone is insufficient.

JSON v1 has these stable fields:

- Envelope: `schema_version` (number, currently `1`), `generated_at` (ISO-8601 string), `partial` (boolean), `sources` (source diagnostics), and `agents` (normalized records). Command errors add a bounded `error` object.
- Source diagnostic: `provider` (`codewith|claude|todos`), `status` (`ok|partial|unavailable|error`), `freshness_at` (the bounded source-operation completion time or `null`), `coverage: {complete, provider_records, projected_records, dropped_records}`, and optional `error: {code, message}`.
- Agent identity/state: `id`, `provider`, `run_id`, `status`, `active`, `started_at`, `updated_at`, `freshness_at`.
- Agent context: `worktree`, `branch`, `last_tool_call: {name, at, summary}`, `goal: {id, title, status}`, `task: {id, short_id, title, status}`, and `profile: {alias}`.
- `gaps` is a sorted array of stable field names for every missing normalized value. Unavailable or withheld fields remain `null`; they are never inferred from prompts, transcripts, paths, matching text, or task assignment.

Output is allowlisted rather than denylist-redacted. Run and task IDs must be canonical lowercase UUIDs, task short IDs use a narrow `E-00104`-style form, statuses use an explicit own closed set, and profile aliases use the configured `accountNNN` form. Timestamps must be strict RFC3339 with an explicit timezone and are emitted as canonical UTC; ambiguous locale strings and missing, invalid, or future observations fail closed. Future live-agent sources must also reject stale liveness evidence. Provider-controlled titles, paths, branches, last-tool text, goal text, raw diagnostics, account IDs, credential labels or values, signed URI components, query or fragment values, and nonprinting Unicode controls are omitted. Human cells are truncated by grapheme cluster.

List coverage remains explicitly unknown until a provider exposes a side-effect-free source limit. Future safe sources may perform at most one bounded operation per selected source, must use the default output limit of 50 and hard maximum of 200, and must mark any source or result truncation `partial: true` with known or unknown dropped coverage. TAI never persists agent data, initializes a provider, mutates locks or tasks, inspects transcripts or prompts, calls a provider once per result, switches profiles, or owns agent lifecycle state.

## Provider Routing

Defaults are local-first and configurable:
Expand Down
14 changes: 14 additions & 0 deletions docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,20 @@ Routing is local-first:

Model IDs are intentionally configuration-driven because availability is time-sensitive.

## Agent Visibility Facade

The `tai agents` surface is separate from model routing. It is a stateless, read-only facade over provider-owned structured APIs that are demonstrably side-effect free. It does not invoke installed Codewith, Claude, or Todos list commands because those routes can initialize state, change permissions, create databases, or mutate expired task locks.

Codewith and Claude remain explicit unavailable sources until they expose a safe structured read surface. Todos list is also unavailable: its task-list implementation performs expired-lock cleanup, and its agent-list API has no authoritative source-level limit. Exact Todos is unavailable because authenticated `/v1` dispatch initializes provider database schema even for GET requests. Provider configuration and credentials are never consulted. Exact show calls only its selected provider and performs zero operations when that source is unsupported. Absence may be reported only from a future proven structured response contract; HTTP status, HTML, redirects, partial responses, malformed bodies, unavailable, truncated, or unproven results remain incomplete.

Normalization is omission-first. Only canonical lowercase UUIDs, narrow task short IDs, explicit own closed-set statuses, strict RFC3339 timestamps with explicit timezone, and `accountNNN` profile aliases may cross the output boundary. Ambiguous locale timestamps and missing, invalid, or future observations fail closed; a future live-agent source must additionally reject stale liveness evidence. Provider-controlled titles, paths, branch names, tool text, goal text, raw diagnostics, URI credentials, query/fragment values, account identifiers, and nonprinting Unicode controls never do. Every null field has a stable named gap, and every source reports explicit complete/returned/dropped coverage.

A future Todos projection must use authoritative provider lease-owner and lease-expiry semantics. Assignment, task status, or a printable agent/session identifier does not establish a live agent. Duplicate state is selected by newest valid observation first, then explicit status precedence and a canonical tie-breaker. When no valid observation exists, comparison continues without `NaN`; reversed inputs produce the same winner and order.

The reusable process boundary used by provider integrations starts termination inside its deadline, continuously tracks Linux descendant PIDs with their process start times, kills tracked descendants even after reparenting, kills the process group and direct child, destroys retained pipes, and resolves around the configured deadline. PID start-time checks prevent a recycled PID from becoming a cleanup target. Output overflow follows the same bounded cleanup. Current agent visibility uses no provider process because no installed command meets the side-effect-free contract.

TAI owns no database, daemon, cache, task assignment, authorization, WorkRun, or agent lifecycle state, and this surface contains no stop, retry, resume, profile-switch, notification, fleet, web, or TUI behavior.

## Safety Policy

Read-only commands may run without confirmation. Writes, network calls, package manager operations, process control, and mutable git operations require confirmation. Destructive operations, credential disclosure, privilege escalation, deploy/publish, and force-push operations are blocked unless the user uses an explicit override.
Loading