# CLI: Agent Workflows

The Keito CLI is agent-friendly because every command supports JSON output, deterministic exit codes, non-interactive authentication, and structured error messages.

For local Codex and Claude Code sessions, the [Keito Agent Skill](/docs/integrations/skills) is the recommended wrapper. It installs hooks and calls `keito time session-record` for you.

## Required Environment

Agents should avoid interactive prompts. Configure credentials with environment variables:

```bash
export KEITO_API_KEY="kto_xxxxx"
export KEITO_ACCOUNT_ID="your_company_id"
```

Then run a preflight check:

```bash
keito auth status --json
```

## Discovery Workflow

Agents should discover project and task IDs before starting work:

```bash
keito projects list --json
keito projects tasks --json
```

Use IDs in automation to avoid ambiguity:

```bash
keito time start \
  --project "project_id_here" \
  --task "task_id_here" \
  --json
```

## Timer Workflow

```bash
keito auth status --json
keito time running --json
keito time start --project "project_id_here" --task "task_id_here" --json
# agent performs work
keito time stop --notes "Implemented OAuth flow" --json
```

Call `keito time running --json` before `time start`. If another timer is running, `time start` exits with code `3` and suggests `keito time stop`.

## Shell Wrapper Pattern

Use a trap so the timer is stopped when the process exits:

```bash
#!/usr/bin/env bash
set -euo pipefail

PROJECT_ID="${KEITO_PROJECT_ID:?Set KEITO_PROJECT_ID}"
TASK_ID="${KEITO_TASK_ID:?Set KEITO_TASK_ID}"
STARTED=0

cleanup() {
  status=$?
  if [ "$STARTED" = "1" ]; then
    if [ "$status" -eq 0 ]; then
      keito time stop --notes "Agent session completed" --json || true
    else
      keito time stop --discard --json || true
    fi
  fi
}

trap cleanup EXIT

keito auth status --json >/dev/null
keito time start --project "$PROJECT_ID" --task "$TASK_ID" --json
STARTED=1

agent-command "$@"
```

This pattern only stops or discards a timer if this script successfully started it.

## Completed Session Workflow

Lifecycle hooks should record completed sessions with `time session-record`:

```bash
keito time session-record \
  --project "project_id_here" \
  --task "task_id_here" \
  --session-id "codex-123" \
  --duration-seconds 5400 \
  --started-at 2026-05-12T09:00:00Z \
  --ended-at 2026-05-12T10:30:00Z \
  --source agent \
  --metadata '{"integration":"custom_agent","agent_type":"codex"}' \
  --json
```

If a session entry with the same session ID already exists for that date and source, the CLI updates it instead of creating a duplicate.

## Error Handling

The CLI writes JSON errors to stderr in JSON mode:

```json
{
  "error": true,
  "code": 3,
  "message": "Conflict: A timer is already running. Stop it first with 'keito time stop'.",
  "suggestion": "keito time stop"
}
```

Agents should use the exit code first and the `suggestion` field second.

| Code | Agent response |
|---|---|
| `1` | Re-check `KEITO_API_KEY` and `KEITO_ACCOUNT_ID` |
| `3` | Inspect `keito time running --json`; stop or reuse the existing timer intentionally |
| `4` | Refresh project/task IDs with discovery commands |
| `5` | Retry after a short delay |
| `6` or `7` | Retry with backoff or fail the session cleanly |
| `8` | Fix config or use environment variables |

## Notes Convention

Use notes to make agent work auditable:

```bash
keito time stop \
  --notes "Codex: implemented CLI docs, ran npm run build" \
  --json
```

Use notes for a concise human-readable summary. Use `--metadata`, `--agent-id`, `--agent-type`, and `--skill` for structured reporting fields.

## When to Use API or SDKs

Use the API, Node SDK, or Python SDK instead of the CLI when you need:

- LLM Usage expense creation
- tighter integration with a long-running application process

See [Agent Integration Overview](/docs/agent-integration/overview) for those patterns.