Metadata-Version: 2.4
Name: codex-agent-framework
Version: 0.1.20
Summary: A lightweight event-driven Codex agent runtime.
Author: Baptiste
License-Expression: MIT
Keywords: agent,ai,codex,openai,tools
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: audioop-lts; python_version >= "3.13"
Requires-Dist: beautifulsoup4
Requires-Dist: codex-backend-sdk
Requires-Dist: fastapi
Requires-Dist: filetype
Requires-Dist: modict
Requires-Dist: mss
Requires-Dist: numpy
Requires-Dist: odfpy
Requires-Dist: openai
Requires-Dist: openpyxl
Requires-Dist: pathspec
Requires-Dist: pillow
Requires-Dist: playwright
Requires-Dist: pydub
Requires-Dist: pypdf
Requires-Dist: pynteract
Requires-Dist: pywinctl
Requires-Dist: python-docx
Requires-Dist: PyYAML
Requires-Dist: regex
Requires-Dist: requests
Requires-Dist: rich
Requires-Dist: textual
Requires-Dist: tiktoken
Requires-Dist: trafilatura
Requires-Dist: uvicorn
Provides-Extra: dev
Requires-Dist: build; extra == "dev"
Requires-Dist: pytest; extra == "dev"
Dynamic: license-file

# codex-agent

`codex-agent-framework` is a local-first Python runtime for building flexible, tool-using AI agents.

It can run as an embedded Python object, an interactive terminal assistant, a long-lived FastAPI/SSE service, a headless CLI worker, or a desktop/tray assistant. The same core `Agent` abstraction powers every mode: persistent sessions, local tools, context providers, slash commands, stateful plugins, event streaming, browser/desktop helpers, document extraction, and optional multimodal capabilities.

> Status: early alpha. APIs are still evolving, and the project intentionally favors clean architecture and flexible composition over long-term compatibility shims.

## Design philosophy

`codex-agent` is designed around one idea: **give users a powerful setup out of the box without locking them into one workflow**.

The default installation includes enough batteries to work immediately: file tools, shell/Python execution, document extraction, memory, todos, wakeups, browser automation, desktop automation, a TUI, a local server, and CLI commands. But each capability is exposed as a module, tool, provider, command, plugin, or runtime extension so users can replace, disable, or add behavior without changing the core.

The architecture tries to keep clear boundaries:

- **Core runtime**: sessions, turns, events, tool execution, server/CLI/runtime adapters, browser and desktop controllers.
- **Built-in tools**: stateless local actions such as reading files, writing/editing, shell/Python execution, image observation, and system helpers.
- **Built-in plugins**: stateful agent-facing capabilities such as memory, planner, scheduler facade, browser facade, and desktop facade.
- **Runtime extensions**: user-owned Python files under `~/.agent_runtime` for tools, providers, commands, and plugins.
- **User configuration/state**: stored in the runtime directory, not mixed into package source files.

The result is meant to be practical for daily use, but still hackable enough for experiments.

## What you can build with it

Typical use cases include:

- a local coding or research assistant that can inspect files, run tests, edit code, and keep context;
- a terminal assistant with persistent sessions and project-specific tools;
- a desktop assistant that can observe browser/desktop state and act through explicit tools;
- a local agent server used by a TUI, tray app, script, or another application;
- a modular testbed for tool registries, runtime plugins, context providers, event-driven UI, and autonomous wakeups.

Because shell, Python, file editing, browser, and desktop tools run with the current user's privileges, this project is powerful but should be treated with care. See [Safety notes](#safety-notes).

## Highlights

- Reusable `Agent` abstraction with persistent JSON sessions.
- Multiple runtime modes: embedded Python, Textual TUI, headless CLI, FastAPI/SSE server, process-backed worker, and optional tray controller.
- Built-in tools for strict file reads, broad content extraction, file writes/edits, Bash, persistent Python, image observation, opening local resources, and server/TUI helpers.
- Stateful built-in plugins for durable semantic memory, named todos, scheduled wakeups, browser automation, and desktop automation.
- Runtime extension folders for user tools, providers, slash commands, and stateful plugins.
- Provider system for live context that is injected into model calls without becoming permanent session history.
- Event bus for UI integrations, tool-call lifecycle, streaming responses, session changes, audio hooks, and automation.
- Local document extraction for folders, text files, URLs, PDFs, DOCX, XLSX, ODT, HTML, and more.
- Optional web search, image generation, voice, LaTeX rendering, browser, desktop, service, and tray integration points.

## Requirements

- Python 3.10 or newer.
- An OpenAI/ChatGPT subscription giving access to the Codex backend API. Core LLM calls use `codex-backend-sdk` via OAuth and do not require a developer API key.
- An `OPENAI_API_KEY` for optional OpenAI-dependent features such as voice models and semantic memory embeddings.
- Optional Linux desktop features need extra system packages:
  - GTK 3 and Ayatana AppIndicator/AppIndicator bindings for the tray;
  - `wmctrl`, `xdotool`, and `xclip` for X11 desktop automation;
  - Playwright-managed Chromium for rendered browser workflows and fallback extraction.

See [`dependencies.txt`](dependencies.txt) for the full optional non-Python dependency list.

## Installation

From PyPI:

```bash
python -m pip install codex-agent-framework
```

From a local checkout:

```bash
python -m pip install -e .
```

For development:

```bash
python -m pip install -e '.[dev]'
```

Install optional Linux system dependencies for browser, desktop, tray, service, terminal, and audio features:

```bash
codex-agent install-system-deps -- -y
```

Bootstrap a local desktop setup by installing system dependencies and then installing/starting the user services:

```bash
codex-agent bootstrap -- -y
```

Useful bootstrap variants:

```bash
codex-agent bootstrap --no-system-deps
codex-agent bootstrap --no-start-service -- -y
codex-agent install-system-deps -- --dry-run --no-tray --no-audio
```

## Quick start

Start an embedded local server and open the terminal TUI:

```bash
codex-agent
```

Start the long-lived local server in the background:

```bash
codex-agent start server
```

By default, `start server` detaches and writes logs under `~/.agent_runtime/logs/server.log`. Use foreground mode when a supervisor such as systemd or launchd should own the process:

```bash
codex-agent start server --foreground
```

Connect a TUI to an already running server:

```bash
codex-agent open tui
```

Start only the tray controller in the background:

```bash
codex-agent start tray
```

The tray log is written to `~/.agent_runtime/logs/tray.log`. Foreground mode is also available:

```bash
codex-agent start tray --foreground
```

Install startup user services for the server and tray controller:

```bash
codex-agent install-service
```

Stop or restart managed services:

```bash
codex-agent stop server
codex-agent restart server
codex-agent stop tray
```

## Choosing a runtime mode

| Mode | Entry point | Best for |
| --- | --- | --- |
| Embedded Python | `Agent(...)` | Scripts, notebooks, tests, custom applications. |
| Interactive TUI | `codex-agent` / `codex-agent open tui` | Daily local assistant usage. |
| FastAPI/SSE server | `codex-agent start server` | Long-lived local service used by UIs or scripts. |
| Headless CLI | `codex-agent run ...` | Automation, CI-like checks, shell pipelines. |
| Process runtime | `codex-agent run --runtime process ...` | Isolated one-shot runs without a pre-existing server. |
| Tray/service setup | `codex-agent bootstrap` / `start tray` | Desktop availability independent of a terminal. |

All modes share the same session, config, runtime directory, tools, providers, commands, and plugins.

## Headless CLI examples

The headless CLI can talk to the running server, or run an isolated one-shot runtime.

Inspect the running server:

```bash
codex-agent status
codex-agent status --json
codex-agent tools
codex-agent config get model
codex-agent sessions list
```

Update runtime config:

```bash
codex-agent config set input_token_limit 128000
codex-agent config set web_search_enabled=false
codex-agent config set model=gpt-5.5
```

Submit a prompt to the running server and stream the answer:

```bash
codex-agent run "Inspect this repository and suggest the next cleanup target."
```

Read a larger prompt from stdin:

```bash
{
  echo "Review this documentation diff for accuracy.";
  git diff -- README.md;
} | codex-agent run --stdin
```

Emit machine-readable events for another process:

```bash
codex-agent run --format ndjson "Run a quick repository health check."
```

Run without a pre-existing server by starting a temporary process runtime:

```bash
codex-agent run --runtime process "Summarize the current project layout."
```

Submit a turn and return immediately:

```bash
codex-agent run --wait-timeout 0 "Continue the long-running audit in the background."
```

Interrupt the current turn:

```bash
codex-agent interrupt "user changed priority"
```

## Python usage

### Minimal embedded agent

```python
from codex_agent import Agent

agent = Agent(
    session="new",
    username="Baptiste",
    voice_enabled=False,
)

answer = agent("Summarize this repository in three practical bullet points.")
print(answer)
```

Resume the latest session interactively:

```python
from codex_agent import Agent

agent = Agent(session="latest", voice_enabled=False)
agent.interact()
```

### Add local tools

Tools are callable actions available to the model. They are useful for things the assistant may need to do: inspect local state, call APIs, run project-specific checks, or manipulate controlled resources.

```python
from pathlib import Path
from codex_agent import Agent, tool

@tool
def list_changed_files() -> list[str]:
    """Return modified or untracked files in the current git repository."""
    import subprocess

    output = subprocess.check_output(
        ["git", "status", "--short"],
        text=True,
    )
    return [line[3:] for line in output.splitlines() if line.strip()]

@tool
def read_project_note(name: str) -> str:
    """Read a project note from ./notes by filename."""
    path = Path("notes", name).resolve()
    notes_dir = Path("notes").resolve()
    if notes_dir not in path.parents:
        raise ValueError("note must stay inside ./notes")
    return path.read_text(encoding="utf-8")

agent = Agent(session="latest", voice_enabled=False)
agent.add_tool(list_changed_files)
agent.add_tool(read_project_note)

agent("Look at the changed files and tell me what needs review first.")
```

### Add live context with providers

Providers inject context before model calls without permanently appending it to the saved conversation. They are best for dynamic or external state: clock, git status, active todos, browser state, desktop screenshots, feature flags, project policy, or environment diagnostics.

A provider may return a string, a `Message` such as `ProviderMessage`, an `ImageMessage`, a list/tuple of those items, or `None` when there is no context to add for the current turn.

A minimal clock provider:

```python
from datetime import datetime
from zoneinfo import ZoneInfo

from codex_agent import Agent, provider

@provider
def current_time():
    now = datetime.now(ZoneInfo("Europe/Paris"))
    return f"Current local time: {now:%Y-%m-%d %H:%M:%S %Z}"

agent = Agent(session="latest", voice_enabled=False)
agent.add_provider(current_time)
agent("Given the current time, should I start a long-running task now?")
```

A project provider can combine stable guidance with freshly computed state:

```python
import subprocess
from codex_agent import Agent, provider

@provider
def repository_context():
    status = subprocess.check_output(
        ["git", "status", "--short"],
        text=True,
    ).strip()
    return f"""
The user is working on codex-agent-framework.
Prefer precise local inspection before editing files.
Do not keep legacy compatibility shims unless explicitly requested.
Current git status:
{status or "clean"}
""".strip()

agent = Agent(session="latest", voice_enabled=False)
agent.add_provider(repository_context)
agent("Plan a safe refactor of the CLI package.")
```

### Add slash commands

Commands are explicit user actions triggered with `/name`. They are useful for direct controls that should not depend on model tool selection.

```python
from codex_agent import Agent, command, get_agent

@command
def repo():
    """Show the active session and current repository hint."""
    agent = get_agent()
    return f"session={agent.current_session_id}; repo=codex-agent"

agent = Agent(session="latest", voice_enabled=False)
agent.add_command(repo)
print(agent("/repo"))
```

### Add stateful plugins

Plugins bundle state, tools, providers, commands, event handlers, hook handlers, and system prompt sections. They are the right abstraction when a feature has its own lifecycle or persistent behavior.

```python
from codex_agent import Plugin, provider, tool

class ProjectNotesPlugin(Plugin):
    name = "project_notes"
    system_prompt = "# Project Notes\nUse project_notes tools when project notes are relevant."

    def __init__(self, agent):
        super().__init__(agent)
        self.notes = []

    @tool
    def remember_note(self, note: str):
        self.notes.append(note)
        return f"Stored {len(self.notes)} note(s)."

    @provider
    def project_notes(self):
        if not self.notes:
            return None
        return "Project notes:\n" + "\n".join(f"- {note}" for note in self.notes)

agent = Agent(session="latest", voice_enabled=False)
agent.plugins_manager.add_plugin(ProjectNotesPlugin(agent))
```

For persistent user plugins loaded at startup, place modules under `~/.agent_runtime/plugins/*.py` instead. See [Runtime extensions](#runtime-extensions).

### Which extension point should I use?

Use the smallest extension point that matches the job:

- use a **tool** when the model should decide when to perform an action;
- use a **provider** when the model should always see fresh context before a response;
- use a **command** when the user should explicitly trigger an operation with `/name`;
- use a **plugin** when a feature needs state, configuration, lifecycle hooks, prompt sections, or a bundle of tools/providers/commands;
- use the **server API** when another process or UI needs to control the agent from outside Python.

This keeps simple customizations simple, while still allowing larger features to grow into proper plugins.

## Runtime directory and sessions

By default, local runtime state is stored in:

```text
~/.agent_runtime
```

Common files and folders:

```text
sessions/          persisted conversation histories as JSON
workfolder/        generated or uploaded working files
commands/          user runtime slash commands
plugins/           user runtime plugins and extension modules
images/            generated or persisted image outputs
browser/           persistent browser profiles and screenshots
logs/              detached server/tray logs
memory.json        durable semantic memory entries
planner.json       persistent named todos
wakeups.json       scheduled autonomous wakeups
agent_config.json  persisted runtime configuration
tui.json           currently registered TUI client process
```

Override the runtime location with:

```bash
AGENT_RUNTIME_DIR=/tmp/my-agent-runtime codex-agent
```

Session behavior:

- `Agent(session="new")` starts a fresh session.
- `Agent(session="latest")` resumes the newest saved session.
- `Agent(session="<session_id>")` loads a specific saved session.
- `Agent(session="/path/to/session.json")` loads a session file directly.

Session IDs are timestamp-based and lexicographically sortable.

Compaction is available through `/compact` and automatic context management. A compacted session keeps backend compaction summaries while pruning compacted raw history from the active session file, so long-running sessions stay manageable.

## Runtime extensions

Runtime extensions are the easiest way to customize an installed agent without forking the package.

At startup, the agent scans:

```text
~/.agent_runtime/plugins/*.py
~/.agent_runtime/commands/*.py
```

Files starting with `_` are ignored. Runtime modules are loaded as ordinary Python modules, so they can import local dependencies available in the agent environment.

Runtime plugins are the user-facing extension unit. A plugin module may expose a `Plugin` subclass, a `register(agent)` function, or — for small extensions — decorated `@tool`, `@provider`, and `@command` callables directly. Set `requires_openai = True` on a module or plugin class to skip loading it when no `OPENAI_API_KEY` is configured.

Startup order is intentionally predictable:

1. built-in plugin modules;
2. runtime plugins from `plugins/`;
3. runtime slash commands from `commands/`;
4. configured server-side tools such as web search or image generation.

Direct runtime `tools/` and `providers/` folders are intentionally not loaded anymore. Simple runtime tools/providers should live in a plugin module; programmatic SDK usage can still call `agent.add_tool()` and `agent.add_provider()` directly.

Example small runtime plugin, `~/.agent_runtime/plugins/git_helpers.py`:

```python
from datetime import datetime
from zoneinfo import ZoneInfo
import subprocess

from codex_agent import provider, tool

@tool
def current_branch() -> str:
    """Return the current git branch."""
    return subprocess.check_output(
        ["git", "branch", "--show-current"],
        text=True,
    ).strip()

@provider
def current_time():
    now = datetime.now(ZoneInfo("Europe/Paris"))
    return f"Current local time: {now:%Y-%m-%d %H:%M:%S %Z}"
```

Example runtime command, `~/.agent_runtime/commands/repo.py`:

```python
from codex_agent import command, get_agent

@command(name="repo")
def repo(args=""):
    agent = get_agent()
    return f"session={agent.current_session_id}; args={args}"
```

Example runtime plugin, `~/.agent_runtime/plugins/project_state.py`:

```python
from codex_agent import Plugin, provider, tool

class ProjectStatePlugin(Plugin):
    name = "project_state"
    system_prompt = "# Project State\nUse project_state tools when project context is needed."

    def __init__(self, agent):
        super().__init__(agent)
        self.notes = []

    @tool
    def remember_project_note(self, note: str):
        self.notes.append(note)
        return f"Stored {len(self.notes)} project note(s)."

    @provider
    def project_notes(self):
        if not self.notes:
            return None
        return "Project notes:\n" + "\n".join(f"- {note}" for note in self.notes)
```

Plugin modules may expose `Plugin` subclasses, or a `register(agent)` function for direct registration:

```python
def register(agent):
    @agent.add_tool(name="hello_project")
    def hello_project():
        return f"Hello from {agent.config.name}"
```

## Built-in tools and plugins

The default agent exposes local tools and plugin tools to the model. Plugin tool names may be prefixed by the plugin namespace to avoid collisions.

| Area | Examples | Purpose |
| --- | --- | --- |
| Files | `read`, `view`, `write`, `edit` | Strict text reads, broad extraction, complete writes, exact-string edits. |
| Shell | `bash`, `python` | Shell commands and persistent Python execution. |
| Vision/system | `observe`, `show`, `open_tui`, `close_tui` | Image observation, opening files/URLs, TUI control. |
| Memory plugin | `memory_add`, `memory_edit`, `memory_delete`, `memory_search`, `/memory_config` | Durable semantic memory, retrieval context, and memory-owned configuration. |
| Planner plugin | `planner_create`, `planner_add`, `planner_check`, `planner_clear` | Persistent named todos surfaced as context. |
| Scheduler plugin | `scheduler_schedule`, `scheduler_cancel`, `scheduler_list`, `scheduler_restart_and_wakeup` | Future turns, periodic wakeups, post-restart continuation. |
| Browser plugin | `browser_open`, `browser_goto`, `browser_click`, `browser_fill`, `browser_press`, ... | Persistent Playwright/Chromium automation with active-tab context. |
| Desktop plugin | `desktop_start_session`, `desktop_run_commands`, `desktop_stop_session` | Screenshot-backed Linux desktop automation. |

Built-ins are intentionally packaged as plugins. Current built-in plugin modules include `files`, `content`, `bash`, `python`, `interface`, `environment`, `memory`, `planner`, `scheduler`, `browser`, and `desktop`.

Built-in plugins are configurable. `None` means load all plugins, an empty list means load none, and an explicit list selects specific plugin module names:

```python
agent = Agent(
    session="latest",
    builtin_plugins=["files", "content", "bash", "python", "memory", "planner", "scheduler"],
)
```

## Built-in slash commands

Inside the interactive agent, commands start with `/`.

Common commands:

```text
/help                         list available commands
/sessions                     list saved sessions
/new_session                  create a new session
/load_session latest          load latest session
/load_session <session_id>    load a specific session
/delete_session <session_id>  delete a session
/next_session                 move to the next/newer session
/previous_session             move to the previous/older session
/compact                      compact completed history turns
/config                       show agent/model config
/config model=gpt-test verbosity=low
/model                        show current model
/model gpt-test               update model
/reasoning high               update reasoning effort
/verbosity low                update verbosity
/voice                        show voice state
/voice off                    toggle voice output
/memory_config                show memory plugin config
/memory_config auto_archive=true max_tokens=4000
/memory_auto_archive on       toggle completed-turn memory archiving
```

The core `/config` command only updates model/context keys such as `model`, `reasoning_effort`, `verbosity`, `input_token_limit`, `max_input_tokens`, and `auto_compact`. Plugin-owned settings stay with their plugin commands, for example `/memory_config`.

Runtime command modules can add more commands from `~/.agent_runtime/commands/*.py`. Runtime plugin modules can also expose commands.

## Local server, TUI, and tray

The server exposes the agent through a FastAPI bridge in `codex_agent.server`. It can run the agent in a separate worker process so HTTP/SSE clients remain responsive while the model is busy. REST endpoints handle state and control operations, while `/events` streams server-sent events for live clients.

Key endpoints:

```text
GET    /health
GET    /status
GET    /config
PATCH  /config
GET    /session
GET    /sessions
POST   /sessions/new
POST   /sessions/{session_id}/load
DELETE /sessions/{session_id}
POST   /sessions/navigate/{direction}
GET    /messages
GET    /tools
GET    /tui
POST   /tui/open
POST   /tui/close
GET    /wakeups
POST   /wakeups
POST   /wakeups/{job_id}/cancel
DELETE /wakeups/{job_id}
GET    /events
GET    /events/replay
POST   /turns
POST   /interrupt
POST   /restart
```

The TUI is a visual client. It connects over SSE, replays the latest turn when opened mid-session, tracks event cursors, and reconnects after server restarts or transient stream loss.

The tray can start or stop the user service, open or close the TUI, and keep the local agent available independently of a terminal.

## Events and hooks

`Agent` exposes an event bus for UI and automation integrations.

```python
from codex_agent import Agent, MessageAddedEvent, ToolCallStartEvent

agent = Agent(session="new", voice_enabled=False)

@agent.on(MessageAddedEvent)
def log_message(event):
    print("message", event.message.type)

@agent.on(ToolCallStartEvent)
def log_tool(event):
    print("tool", event.name)
```

Useful exported events include:

- `MessageAddedEvent`
- `MessageSubmittedEvent`
- `AssistantTurnStartEvent` / `AssistantTurnEndEvent` / `AssistantTurnErrorEvent`
- `AssistantStepStartEvent` / `AssistantStepEndEvent`
- `ResponseStartEvent` / `ResponseContentDeltaEvent` / `ResponseDoneEvent`
- `ToolCallStartEvent` / `ToolCallDoneEvent`
- `SessionLoadedEvent` / `SessionDeletedEvent`
- `AssistantInterruptedEvent`
- `AudioPlaybackEvent`

Plugins can also register event and hook handlers with decorators:

```python
from codex_agent import AssistantTurnEndEvent, Plugin, event_handler, hook_handler

class AuditPlugin(Plugin):
    name = "audit"

    def __init__(self, agent):
        super().__init__(agent)
        self.completed_turns = 0

    @event_handler(AssistantTurnEndEvent)
    def count_turn(self, event):
        self.completed_turns += 1

    @hook_handler("provider.call.after")
    def redact_provider_output(self, context):
        output = context.payload.output
        if isinstance(output, str):
            context.payload.output = output.replace("SECRET", "<redacted>")
```

Hooks are named extension points with mutable context objects. They allow advanced integrations without hard-coding plugin-specific behavior into the core.

## Configuration

`Agent` accepts configuration through keyword arguments:

```python
from codex_agent import Agent

agent = Agent(
    session="latest",
    model="gpt-5.4",
    reasoning_effort="medium",
    verbosity="medium",
    input_token_limit=128000,
    auto_compact=True,
    web_search_enabled=False,
    image_generation_enabled=False,
    voice_enabled=False,
    builtin_plugins=None,    # None = all built-in plugins, [] = none, or explicit plugin names
    custom_plugins=None,     # None = all runtime plugins from ~/.agent_runtime/plugins, [] = none
)
```

Agent-level configuration can also be changed through slash commands, the HTTP API, or the CLI:

```bash
codex-agent config get
codex-agent config get input_token_limit
codex-agent config set input_token_limit 128000
codex-agent config set voice_enabled=false
codex-agent config set builtin_plugins='["memory", "planner", "scheduler"]'
```

Agent-level configuration is persisted to `agent_config.json` in the runtime directory when saved through agent helpers, slash commands, the HTTP API, or `codex-agent config set`.

Plugin-specific technical settings stay with their plugin state instead of being mixed into `AgentConfig`. For example, the memory plugin persists `auto_archive`, embedding precision/dimensions, ranking decay, and retrieval token budget in `memory.json`, and exposes its own slash commands:

```text
/memory_config
/memory_config auto_archive=true max_tokens=4000 dimensions=128
/memory_auto_archive off
```

Use `--no-save` with the CLI for transient agent-level updates:

```bash
codex-agent config set --no-save verbosity low
```

## Project layout

```text
codex_agent/                      Python package
codex_agent/agent.py              Central Agent object and high-level public methods
codex_agent/mainloop.py           Turn loop, assistant calls, tool execution, pending results
codex_agent/context.py            System/session/provider context assembly and token budgeting
codex_agent/sessions.py           Persistent JSON sessions, compaction, session navigation
codex_agent/message.py            Message types and Responses API formatting
codex_agent/ai.py                 Codex backend / OpenAI-facing client helpers
codex_agent/agent_runtime.py      Runtime abstraction used by server, CLI, and process workers
codex_agent/runtime.py            Agent-facing runtime management helpers
codex_agent/tool.py               Tool model, decorators, tool manager, and server-tool helpers
codex_agent/provider.py           Provider decorator and provider manager
codex_agent/plugin.py             Stateful plugin base class and plugin manager
codex_agent/command.py            Slash command registry and command dispatch
codex_agent/hooks.py              Generic runtime hook manager
codex_agent/event.py              Event classes and event bus
codex_agent/browser.py            Core browser controller backend
codex_agent/desktop.py            Core desktop controller backend
codex_agent/scheduler.py          Core scheduled wakeup primitive
codex_agent/server/               FastAPI REST/SSE bridge package
codex_agent/tui/                  Textual TUI client and lifecycle helpers
codex_agent/cli/                  Root CLI, headless commands, and runtime runners
codex_agent/builtin_plugins/      Built-in tools/providers/commands grouped as plugins
codex_agent/builtin_commands.py   Built-in slash commands
codex_agent/get_text/             Document extraction helpers
codex_agent/prompts/              Packaged system prompts
codex_agent/service.py            systemd/launchd user service helpers
codex_agent/tray.py               GTK tray controller
tests/                            Test suite
scripts/                          Source scripts mirrored into package data
pyproject.toml                    Package metadata and build config
MANIFEST.in                       Source distribution includes
```

## Testing

Run the full suite:

```bash
python -m pytest
```

Run lightweight static checks used during local cleanup:

```bash
python -m pyflakes codex_agent tests
```

The tests isolate `AGENT_RUNTIME_DIR` automatically, so they should not create or resume sessions from your real `~/.agent_runtime`.

The current tree validates at:

```text
456 passed
```

The published `0.1.20` release was validated at:

```text
456 passed
```

## Packaging

Build source and wheel distributions with:

```bash
python -m pip install build twine
rm -rf build dist *.egg-info
python -m build
python -m twine check dist/*
```

The distribution includes prompt text files, `codex_agent/get_text/default_gitignore`, and the packaged Linux system dependency installer through package data and `MANIFEST.in`.

## Recent changes

- `0.1.20`: make runtime plugins the single user-facing extension unit for tools/providers/commands, remove legacy direct runtime tool/provider loading, split tool/provider managers, and keep system-prompt templating on an explicit minimal namespace.
- `0.1.19`: prune compacted raw session history after compaction, keep only the latest compaction anchor plus the new compaction and any unfinished remainder, and drop older redundant compaction summaries from active session files.
- `0.1.18`: make `start server/tray` detach by default, move durable memory fully into the memory plugin, keep wakeups as a core runtime primitive, expose RAG memory timestamps/sources, and move browser/desktop backend controllers into core modules with plugins as facades.
- `0.1.17`: reorganize the TUI and FastAPI server into dedicated `codex_agent.tui` and `codex_agent.server` packages, remove obsolete message payload fields, and clean unused imports.
- `0.1.16`: tolerate missing OpenAI API keys at startup by disabling OpenAI-dependent voice and memory features, and skip memory archiving when the memory plugin is unavailable.
- `0.1.15`: add the `AgentRuntime` interface for server/CLI/process adapters, split the CLI into a package with headless runtime commands, add `codex-agent config set` plus `PATCH /config`, and make built-in tools/providers/plugins configurable.
- `0.1.14`: add HookManager infrastructure, planner/scheduler robustness fixes, documented system dependencies, `codex-agent install-system-deps`, `codex-agent bootstrap`, and improved TUI SSE reconnect/replay handling.
- `0.1.12`: add a persistent Playwright/Chromium browser controller with tab navigation, DOM/action snapshots, screenshots, form/click/key tools, and `browser_goto(url)` for active-tab navigation.
- `0.1.11`: split strict line-numbered UTF-8 `read` from unnumbered extracted `view`, preserve blank lines in read snippets, and show persistent+temporary message counts in the TUI status bar.
- `0.1.10`: persist only backend compaction summaries, drop bulky compacted conversation payloads, and refresh context status after compaction.
- `0.1.9`: maintenance packaging release after validating the local execution environment and deploy workflow.
- `0.1.8`: scope TUI replay/SSE catch-up to the active session and make bash/python subprocesses inherit the project Python environment, including service-launched agents.
- `0.1.7`: add durable RAG memory, scheduled wakeups, process-isolated server runtime, tray/service controls, robust SSE replay/reconnect, richer TUI status, and improved token estimates.
- `0.1.6`: add the FastAPI REST/SSE bridge, HTTP/SSE client, async-style agent mainloop, and decoupled TUI operation.

See [`CHANGELOG.md`](CHANGELOG.md) for the full history.

## Safety notes

This project is designed to let an AI assistant act on the local machine. That is useful, but potentially risky.

Recommended practices:

- Use a dedicated runtime directory for experiments.
- Review tool calls before enabling autonomous workflows.
- Avoid running the agent with elevated privileges.
- Keep secrets out of prompts, logs, committed runtime files, and shared session exports.
- Prefer temporary workfolders in tests and demos.
- Treat browser and desktop automation as real user actions.
- Keep user runtime plugins under version control if they become important to your workflow.

## License

MIT. See [LICENSE](LICENSE).
