Metadata-Version: 2.4
Name: atgent
Version: 0.3.0
Summary: Email an idea. Your local coding agent gets to work.
Author: Compound Labs
License-Expression: MIT
Project-URL: Homepage, https://github.com/kyisaiah47/atgent
Project-URL: Repository, https://github.com/kyisaiah47/atgent
Project-URL: Issues, https://github.com/kyisaiah47/atgent/issues
Project-URL: Security, https://github.com/kyisaiah47/atgent/security/policy
Keywords: codex,claude-code,email,automation
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

# @gent

**Email an idea. Your coding agent gets to work.**

Send a task from your phone. Codex or Claude Code runs on your own computer and emails you the result. Reply to continue the same session.

No SSH, mobile terminal app, port forwarding, or public endpoint. Repositories and agent sign-ins stay on your computer; task text and results travel through Gmail and your chosen agent provider.

MIT licensed. Requirements: Gmail or Google Workspace with IMAP access, macOS/Linux, Python 3.11+, and uv. macOS is live-tested; Linux has automated coverage. Your computer must stay awake and online. Install and sign in to Codex or Claude Code first; Claude needs the `--permission-prompts` option (v2.1.259+). Existing subscriptions, limits, and permissions apply.

## Send a task

```text
To: you+agents@gmail.com
Subject: Codex: improve the signup form

Find the confusing parts of the signup form, improve them,
and run the relevant checks. Leave the changes ready to review.
```

Choose Claude Code with `Claude: your task`. Target a configured project with `Codex/website: your task`. Pick a model for one task by putting its name in square brackets before the colon:

```text
Claude [opus]: review the auth flow
Codex/website [gpt-6.1-sol]: fix the build
Claude/mailbox [haiku]: summarise the open issues
```

The model applies to every reply in that thread and to a local resume. Without brackets the agent's default model from the config is used. Model names may contain letters, numbers, `.`, `_` and `-`; any other subject is ignored. Agent names are case insensitive; project aliases are case sensitive.

You'll receive **Queued**, **Started**, and a result in the email thread. Reply with your next instruction to continue the exact session. Reply `status` for progress or `stop` to cancel queued turns and stop the running process. File changes already made are retained.

Plain text and HTML-only email are accepted. Write replies above the quoted conversation. HTML is converted to text without executing active content; recognized quoted threads are removed. Attachments are saved under the task's private local state directory and their paths are included in the agent prompt. Attachments are untrusted input and are not automatically executed.

Default limits: 20 MiB per raw message, 5 MiB per attachment, 10 MiB combined attachments, 10 attachments, and 32,000 characters of task text. Oversized or unsupported nested attachments cause the message to be ignored. Byte/count limits can be lowered with `max_message_bytes`, `max_attachment_bytes`, `max_attachments_bytes`, and `max_attachments`.

## Install

With [uv](https://docs.astral.sh/uv/getting-started/installation/) installed:

```sh
uv tool install atgent
atgent init
```

The old `agent-mailbox` command still works and runs the same program.

`init` asks for your Gmail address, how the runner signs in (app password from the Keychain, a command or an environment variable, or your own OAuth client), your project folders, and which installed agents to use with their default models. It writes `~/.config/agent-mailbox/config.json` without any secret and offers to run `doctor`. For a script, `atgent init --email you@gmail.com --project /absolute/path/to/project` writes a minimal config without questions.

Change an agent's default model later with `atgent model claude opus`, or `atgent model codex default` to return to Codex's own default.

Choose an app password or your own Gmail OAuth desktop client. An app password is simpler when your account permits it. Follow Google's [app-password setup](https://support.google.com/accounts/answer/185833). Managed accounts and some security settings block app passwords; OAuth can still require administrator consent. See [Gmail OAuth setup](docs/oauth.md) for the alternative.

Keep the password in your password manager or OS keychain. In `~/.config/agent-mailbox/config.json`, set `password_command` to an argument array. For example, after storing the password in a macOS Keychain item named `atgent`:

```json
"password_command": ["security", "find-generic-password", "-s", "atgent", "-w"]
```

Alternatively set `AGENT_MAILBOX_PASSWORD` in your environment. The generated config references that variable, never the password. A password command takes priority. Don't put literal passwords in command arguments or commit local configuration.

```sh
atgent doctor
atgent run
```

`doctor` authenticates IMAP and SMTP without sending mail and checks CLI installation. It doesn't prove remaining agent capacity. On the first successful poll, the runner skips historical Sent mail and arms new-message intake. Send your task after this happens.

To run detached without opening a window:

```sh
atgent start
atgent status
atgent shutdown
```

This is an ordinary process, with no automatic login/reboot persistence. Logs and private state are under `state/` beside your config. `start` reports process creation; inspect the log and use `doctor` to verify access.

## Automatic startup (optional)

```sh
atgent shutdown
atgent install-service
atgent service-status
atgent uninstall-service
```

Installation registers a user LaunchAgent on macOS or a systemd user unit on Linux. It starts at user login and restarts after failure. Linux startup before login requires user lingering configured separately. macOS does not run the job before login. Keep the Python installation, config path, CLI executables, and credential resolver available at the same paths. Service and manual runners share one lock. Shut down an ordinary runner before installing. `shutdown` stops the current runner; `uninstall-service` also removes automatic startup. Neither undoes task changes. The computer must remain awake and connected.

## Projects and permissions

Only configured project aliases can be selected. Edit your local config:

```json
"projects": {
  "main": "/absolute/path/to/project",
  "website": {
    "path": "/absolute/path/to/another/project",
    "sandbox": "read-only",
    "agents": {
      "codex": {"approval_policy": "on-request", "approvals": "email"}
    }
  }
},
"default_project": "main"
```

Set `max_workers` to run tasks concurrently (default 1, maximum 32). By default each project directory runs one task at a time, including aliases that resolve to the same directory. Set `"concurrent": true` on a project (`"lab": {"path": "/absolute/path", "concurrent": true}`) to let separate tasks run side by side in it, for example a folder that holds many repositories. Turns in the same thread or session always run one at a time. The runner does not coordinate other local editors or separately launched agents, and concurrent tasks in one directory can edit the same files.

Codex settings can be global (`codex_sandbox`, `codex_approval_policy`), per agent (`agents.codex.sandbox` / `approval_policy`), per project, or per project-agent as above. Precedence is project-agent, project, agent, global, then defaults. Sandboxes are `read-only`, `workspace-write`, or `danger-full-access`; approval policies are `never`, `on-request`, `untrusted`, or `on-failure`, subject to installed CLI support. `approvals` can likewise be overridden by agent/project. Choose elevated access deliberately.

With approvals off (the default), Codex uses `workspace-write` and doesn't wait for approval prompts. Set `codex_sandbox` to `read-only` for a read-only baseline. Existing Codex/project instructions still apply; sandboxing isn't bypassed. Privileged or network-dependent work may be blocked by CLI policy.

With approvals off, Claude uses `dontAsk` by default. It permits Read/Edit/Write/Glob/Grep/Bash/WebFetch tools and denies actions that require interactive approval because no one is present to answer a prompt. The runner provides no OS sandbox for Claude. Bash runs with the same access as an ordinary local session, bounded only by the configured project directory and whatever rules exist in Claude's own settings. Project selection sets Claude's working directory, not a filesystem security boundary. If a turn finishes with denied requests, its status is `needs_review`, and completed work remains.

Set `"claude_permission_mode": "bypassPermissions"` globally, per agent, per project, or per project-agent. It uses the same precedence and keys as the Codex settings above. This setting stops `dontAsk` from denying actions during a task. It runs Claude with `--dangerously-skip-permissions`, which allows every tool call without a prompt or per-call review, including calls that `dontAsk` would otherwise deny. It is the only setting that removes the denials caused by this mode, and no narrower setting exists. Config validation rejects combining it with `"approvals": "email"` because full bypass conflicts with human-reviewed actions. Choose it deliberately, and prefer scoping it to one trusted project instead of using the global default.

Existing CLI sign-ins are reused. Inherited provider API-key variables are removed; explicit agent `env` entries can opt in. No subscription is created and there is no silent fallback to another agent. For an existing Claude account, set `CLAUDE_CONFIG_DIR` in `agents.claude.env`. Keep that account stable across replies.

## Approve actions by email (optional)

Add this to your local configuration and restart the runner when no task is active:

```json
"approvals": "email",
"approval_timeout_seconds": 900
```

When the CLI needs permission, the same running turn pauses. An email displays the complete native action, working directory, reason, task and turn identifiers, and a SHA256 digest. Reply directly to that approval email with `approve` or `deny`, or in its task thread with exactly `approve TOKEN` or `deny TOKEN`. Ordinary replies and quoted messages never count as approval. You can still send `status` or `stop` while waiting.

A grant applies to one concrete request, never a session or future command. Wrong-thread, expired, duplicate, cancelled, and restart-invalidated decisions cannot authorize it. No answer means denial after the timeout. The runner keeps reading mail while the agent waits and never restarts the task to implement approval. Previously completed external actions are not replayed. Native policies may still block an approved request.

Codex uses its native stdio app-server with `on-request` approval policy and the configured sandbox. Commands already permitted by that sandbox may run without an email; use `"codex_sandbox": "read-only"` for a stricter baseline. File-change requests need a complete native diff; requests for session-wide root grants, terminal input, unsupported permission types, and actions too large to display fully are refused.

Claude uses its native stream-json host permission channel with `default` mode. Existing allow rules can run without a new email; hard deny rules remain enforced. No broad tool allowlist is added in email mode. This is a bundled protocol adapter: **no separately installed agent plugin or phone app** is required. Use a current CLI supporting host permission prompts (Claude Code v2.1.259+ and Codex app-server). If the native channel is unavailable, the turn fails closed rather than falling back to bypass permissions.

Set `"approvals": "off"` to retain the original noninteractive behavior. This option does not enable bypass mode, change global CLI settings, or remove existing hooks. See [approval behavior and limits](docs/approvals.md).

## Pick up locally

```sh
atgent list            # pick a session with the arrow keys, Enter opens it here
atgent open TASK_ID    # resume one task's session in this terminal
```

Each row shows the agent, the model, the turn status, how long ago it last ran and the subject; the bottom pane previews the selected task's last reply. Press `/` to filter, Esc to clear the filter, and `q` to quit. The session opens in its project directory with the agent's configured environment and model, so Claude sessions that use their own `CLAUDE_CONFIG_DIR` resume correctly. The resumed agent is told that you are now in the terminal, so it answers there instead of by email. If the task is still running from email, `list` and `open` ask whether to stop it first, then wait for the runner to release the session. `atgent pickup TASK_ID` prints the plain resume command without running it. Pause the runner during an extended local handoff; don't run local and email turns simultaneously against the same session.

## Reliability and trust

- Intake reads Gmail's authenticated **Sent** special-use folder, not Inbox. A spoofed incoming sender can't submit a task. Anyone able to append to your Sent folder has equivalent task-submission authority; protect your Gmail account and app password.
- Task messages must be authored by the mailbox owner and addressed to the task alias. Automatic notifications are excluded to prevent loops.
- Message IDs are deduplicated in SQLite. References map replies to exact sessions. Unmatched replies never become new tasks.
- Configured workers run different project directories concurrently. The scheduler serializes each project directory and session within this runner.
- An exclusive process lock prevents a second runner. Interrupted turns are held rather than replayed. Recorded orphan process groups are stopped only after matching PID and OS start time. A small crash window exists between process creation and identity recording; inspect the machine after an unclean shutdown.
- SMTP sends with uncertain acceptance aren't blindly resent. `status` shows delivery state; check Sent mail as needed. A task can finish even when its notification fails.
- A Sent-folder UID reset pauses intake. Shut down, review pending mail, then explicitly skip historical mail with `atgent rebaseline`.
- Local state contains prompts, attachments, approvals, and results and is created with private permissions. Agent session transcripts follow their CLI's normal retention policy. Neither belongs in the public repository.

There is no hosted inbox, mobile live-terminal UI, or remote browser-authentication handoff in this version. Email approvals authorize one displayed action; `approve all` is unsupported. Review work before publishing or deploying it.

## Development

```sh
PYTHONPATH=src python3 -m unittest discover -s tests -v
```

For a source checkout, install with `uv tool install .`. See [contributing](CONTRIBUTING.md) for development checks.

Automated tests use temporary databases and fake subprocesses; they don't send email or invoke model APIs. See [architecture](docs/architecture.md), [security](SECURITY.md), and [launch package](docs/launch.md).
