codex-agent-framework 0.1.28__tar.gz → 0.1.30__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) hide show
  1. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/CHANGELOG.md +13 -0
  2. codex_agent_framework-0.1.30/PKG-INFO +220 -0
  3. codex_agent_framework-0.1.30/README.md +171 -0
  4. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/agent.py +52 -2
  5. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/agent_runtime.py +7 -6
  6. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/builtin_commands.py +2 -2
  7. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/builtin_plugins/bash/__init__.py +2 -1
  8. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/builtin_plugins/content/system.py +1 -1
  9. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/builtin_plugins/content/vision.py +19 -3
  10. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/builtin_plugins/environment/__init__.py +62 -1
  11. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/builtin_plugins/files/tools.py +6 -3
  12. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/builtin_plugins/python/__init__.py +6 -3
  13. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/client.py +81 -14
  14. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/config.py +2 -0
  15. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/mainloop.py +4 -1
  16. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/server/app.py +7 -2
  17. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/server/core.py +2 -2
  18. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/sessions.py +44 -8
  19. codex_agent_framework-0.1.30/codex_agent/tui/app.py +226 -0
  20. codex_agent_framework-0.1.30/codex_agent/tui/chat.py +362 -0
  21. codex_agent_framework-0.1.30/codex_agent/tui/log.py +225 -0
  22. codex_agent_framework-0.1.30/codex_agent/tui/state.py +148 -0
  23. codex_agent_framework-0.1.30/codex_agent/tui/status_bar.py +86 -0
  24. codex_agent_framework-0.1.30/codex_agent/tui/style.py +56 -0
  25. codex_agent_framework-0.1.30/codex_agent/tui/transcript.py +337 -0
  26. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/utils.py +13 -5
  27. codex_agent_framework-0.1.30/codex_agent/version.py +1 -0
  28. codex_agent_framework-0.1.30/codex_agent_framework.egg-info/PKG-INFO +220 -0
  29. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent_framework.egg-info/SOURCES.txt +6 -0
  30. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent_framework.egg-info/requires.txt +1 -1
  31. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/pyproject.toml +2 -2
  32. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/tests/test_agent.py +262 -4
  33. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/tests/test_chat.py +293 -106
  34. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/tests/test_client.py +167 -2
  35. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/tests/test_server.py +37 -1
  36. codex_agent_framework-0.1.28/PKG-INFO +0 -655
  37. codex_agent_framework-0.1.28/README.md +0 -606
  38. codex_agent_framework-0.1.28/codex_agent/tui/chat.py +0 -1293
  39. codex_agent_framework-0.1.28/codex_agent/version.py +0 -1
  40. codex_agent_framework-0.1.28/codex_agent_framework.egg-info/PKG-INFO +0 -655
  41. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/LICENSE +0 -0
  42. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/MANIFEST.in +0 -0
  43. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/__init__.py +0 -0
  44. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/__main__.py +0 -0
  45. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/ai.py +0 -0
  46. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/browser.py +0 -0
  47. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/builtin_plugins/__init__.py +0 -0
  48. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/builtin_plugins/bash/requirements.txt +0 -0
  49. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/builtin_plugins/browser/__init__.py +0 -0
  50. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/builtin_plugins/browser/requirements.txt +0 -0
  51. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/builtin_plugins/content/__init__.py +0 -0
  52. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/builtin_plugins/content/requirements.txt +0 -0
  53. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/builtin_plugins/context/__init__.py +0 -0
  54. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/builtin_plugins/desktop/__init__.py +0 -0
  55. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/builtin_plugins/desktop/requirements.txt +0 -0
  56. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/builtin_plugins/environment/requirements.txt +0 -0
  57. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/builtin_plugins/files/__init__.py +0 -0
  58. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/builtin_plugins/files/requirements.txt +0 -0
  59. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/builtin_plugins/image_generation/__init__.py +0 -0
  60. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/builtin_plugins/image_generation/image_generation_system_prompt.txt +0 -0
  61. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/builtin_plugins/image_generation/requirements.txt +0 -0
  62. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/builtin_plugins/interface/__init__.py +0 -0
  63. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/builtin_plugins/interface/requirements.txt +0 -0
  64. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/builtin_plugins/memory/__init__.py +0 -0
  65. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/builtin_plugins/memory/requirements.txt +0 -0
  66. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/builtin_plugins/planner/__init__.py +0 -0
  67. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/builtin_plugins/planner/requirements.txt +0 -0
  68. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/builtin_plugins/python/requirements.txt +0 -0
  69. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/builtin_plugins/realtime/__init__.py +0 -0
  70. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/builtin_plugins/realtime/audio.py +0 -0
  71. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/builtin_plugins/realtime/bridge.py +0 -0
  72. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/builtin_plugins/realtime/manager.py +0 -0
  73. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/builtin_plugins/realtime/requirements.txt +0 -0
  74. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/builtin_plugins/realtime/session.py +0 -0
  75. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/builtin_plugins/scheduler/__init__.py +0 -0
  76. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/builtin_plugins/scheduler/requirements.txt +0 -0
  77. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/builtin_plugins/subagents/__init__.py +0 -0
  78. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/builtin_plugins/subagents/profiles/explorer.json +0 -0
  79. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/builtin_plugins/subagents/requirements.txt +0 -0
  80. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/builtin_plugins/tts/__init__.py +0 -0
  81. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/builtin_plugins/tts/requirements.txt +0 -0
  82. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/cli/__init__.py +0 -0
  83. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/cli/headless.py +0 -0
  84. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/cli/main.py +0 -0
  85. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/cli/output.py +0 -0
  86. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/cli/root.py +0 -0
  87. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/cli/runner.py +0 -0
  88. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/command.py +0 -0
  89. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/context.py +0 -0
  90. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/desktop.py +0 -0
  91. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/event.py +0 -0
  92. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/get_text/__init__.py +0 -0
  93. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/get_text/default_gitignore +0 -0
  94. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/get_text/get_text.py +0 -0
  95. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/get_text/simpler_get_text.py +0 -0
  96. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/hooks.py +0 -0
  97. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/image.py +0 -0
  98. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/latex.py +0 -0
  99. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/message.py +0 -0
  100. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/plugin.py +0 -0
  101. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/prompts/system_prompt.txt +0 -0
  102. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/provider.py +0 -0
  103. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/runtime.py +0 -0
  104. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/scheduler.py +0 -0
  105. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/scripts/install-system-dependencies.sh +0 -0
  106. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/server/__init__.py +0 -0
  107. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/service.py +0 -0
  108. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/status.py +0 -0
  109. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/stream.py +0 -0
  110. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/stream_utils.py +0 -0
  111. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/tool.py +0 -0
  112. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/tray.py +0 -0
  113. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/tui/__init__.py +0 -0
  114. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/tui/lifecycle.py +0 -0
  115. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent/worker.py +0 -0
  116. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent_framework.egg-info/dependency_links.txt +0 -0
  117. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent_framework.egg-info/entry_points.txt +0 -0
  118. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/codex_agent_framework.egg-info/top_level.txt +0 -0
  119. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/dependencies.txt +0 -0
  120. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/setup.cfg +0 -0
  121. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/tests/test_agent_runtime.py +0 -0
  122. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/tests/test_ai.py +0 -0
  123. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/tests/test_browser.py +0 -0
  124. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/tests/test_builtin_config.py +0 -0
  125. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/tests/test_cli.py +0 -0
  126. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/tests/test_cli_headless.py +0 -0
  127. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/tests/test_cli_root.py +0 -0
  128. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/tests/test_events.py +0 -0
  129. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/tests/test_get_text_browser.py +0 -0
  130. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/tests/test_hooks.py +0 -0
  131. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/tests/test_image_message.py +0 -0
  132. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/tests/test_local_desktop.py +0 -0
  133. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/tests/test_memory.py +0 -0
  134. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/tests/test_messages.py +0 -0
  135. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/tests/test_planner.py +0 -0
  136. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/tests/test_scheduler.py +0 -0
  137. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/tests/test_service.py +0 -0
  138. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/tests/test_tray.py +0 -0
  139. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/tests/test_tui.py +0 -0
  140. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/tests/test_utils.py +0 -0
  141. {codex_agent_framework-0.1.28 → codex_agent_framework-0.1.30}/tests/test_worker.py +0 -0
@@ -4,6 +4,19 @@ All notable changes to this project will be documented in this file.
4
4
 
5
5
  This project loosely follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and uses semantic versioning where practical.
6
6
 
7
+ ## [0.1.29] - 2026-05-15
8
+ ### Changed
9
+ - Split the Textual TUI implementation into focused modules for app wiring, transcript rendering, status display, styling, log windowing, and render state.
10
+ - Replace ad hoc TUI app calls and duplicate display tracking with a typed bridge and centralized deduplication state.
11
+ - Move terminal resize handling into the Textual app so transcript, input sizing, layout cache, and status refresh stay coordinated.
12
+
13
+ ### Fixed
14
+ - Invalidate selectable log layout metrics cleanly on terminal resize to keep wrapped transcript rendering accurate.
15
+ - Keep TUI turn rendering state scoped to the active turn without leaking tool or slash-command display markers.
16
+
17
+ ### Tests
18
+ - Update TUI/chat regression coverage for the extracted bridge/state modules and resize handling; the current suite validates at 577 passed.
19
+
7
20
  ## [0.1.28] - 2026-05-15
8
21
  ### Added
9
22
  - Add `StreamManager` as a dedicated stream-processing manager and expose it through the package API.
@@ -0,0 +1,220 @@
1
+ Metadata-Version: 2.4
2
+ Name: codex-agent-framework
3
+ Version: 0.1.30
4
+ Summary: A lightweight event-driven Codex agent runtime.
5
+ Author: Baptiste
6
+ License-Expression: MIT
7
+ Keywords: agent,ai,codex,openai,tools
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.10
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
15
+ Requires-Python: >=3.10
16
+ Description-Content-Type: text/markdown
17
+ License-File: LICENSE
18
+ Requires-Dist: audioop-lts; python_version >= "3.13"
19
+ Requires-Dist: beautifulsoup4
20
+ Requires-Dist: codex-backend-sdk>=0.3.1
21
+ Requires-Dist: fastapi
22
+ Requires-Dist: filetype
23
+ Requires-Dist: modict
24
+ Requires-Dist: mss
25
+ Requires-Dist: numpy
26
+ Requires-Dist: odfpy
27
+ Requires-Dist: openai
28
+ Requires-Dist: openpyxl
29
+ Requires-Dist: pathspec
30
+ Requires-Dist: pillow
31
+ Requires-Dist: playwright
32
+ Requires-Dist: pydub
33
+ Requires-Dist: pypdf
34
+ Requires-Dist: pynteract>=0.1.4
35
+ Requires-Dist: pywinctl
36
+ Requires-Dist: python-docx
37
+ Requires-Dist: PyYAML
38
+ Requires-Dist: regex
39
+ Requires-Dist: requests
40
+ Requires-Dist: rich
41
+ Requires-Dist: textual
42
+ Requires-Dist: tiktoken
43
+ Requires-Dist: trafilatura
44
+ Requires-Dist: uvicorn
45
+ Provides-Extra: dev
46
+ Requires-Dist: build; extra == "dev"
47
+ Requires-Dist: pytest; extra == "dev"
48
+ Dynamic: license-file
49
+
50
+ # codex-agent
51
+
52
+ `codex-agent-framework` is a local-first Python framework for building and running tool-using AI agents.
53
+
54
+ Use it as a ready-to-run terminal assistant, or import `Agent` when you want to build your own agentic workflow in Python.
55
+
56
+ > Early alpha: APIs are still evolving and breaking changes are expected while the architecture settles.
57
+
58
+ ## Why codex-agent?
59
+
60
+ codex-agent is meant to be a transparent, hackable local harness for power users and developers:
61
+
62
+ - **Local-first runtime**: sessions, memory, config, plugins, logs, and work files live under your local runtime directory.
63
+ - **Multiple entry points**: TUI, headless CLI, Python SDK, and local FastAPI server.
64
+ - **Plugin-first design**: tools, providers, slash commands, hooks, events, prompt sections, and stream processors are extension points.
65
+ - **Observable agent loop**: turns return structured results and emit events that UIs and integrations can stream.
66
+ - **Built-in practical tools**: files, shell, Python, context, memory, planner, scheduler, browser/desktop automation, and subagents.
67
+
68
+ ## Quick start
69
+
70
+ Install the package:
71
+
72
+ ```bash
73
+ python -m pip install codex-agent-framework
74
+ ```
75
+
76
+ For the recommended local setup, run:
77
+
78
+ ```bash
79
+ codex-agent bootstrap -- -y
80
+ ```
81
+
82
+ `bootstrap` installs desktop/browser/tray dependencies, installs the user services, and starts them. It is currently aimed mostly at Debian-like Linux systems. Use an X11 session for the best desktop automation support; Wayland is fine if you do not use the desktop plugin.
83
+
84
+ Open the assistant:
85
+
86
+ ```bash
87
+ codex-agent
88
+ ```
89
+
90
+ If a local agent server is already running, the TUI connects to it. Otherwise `codex-agent` starts a temporary server for that TUI session and shuts it down when the TUI exits. New sessions are anchored to the directory where you launch `codex-agent`; see [CLI and runtime](docs/cli-and-runtime.md#session-root-and-working-directory).
91
+
92
+ Inside the TUI, start with:
93
+
94
+ ```text
95
+ /help
96
+ /sessions
97
+ /new_session
98
+ /load_session latest
99
+ /compact
100
+ /config
101
+ ```
102
+
103
+ Use `/compact` when a long session needs to reduce its active context. It keeps a backend summary and prunes older raw history from the active session file.
104
+
105
+ ## Python in 30 seconds
106
+
107
+ ```python
108
+ from codex_agent import Agent
109
+
110
+ agent = Agent(session="new")
111
+ turn = agent("Summarize this repository in three practical bullet points.")
112
+
113
+ print(turn.result)
114
+ ```
115
+
116
+ Stream live events when building your own UI or integration:
117
+
118
+ ```python
119
+ from codex_agent import Agent, ResponseContentDeltaEvent
120
+
121
+ agent = Agent(session="new")
122
+ stream = agent.stream("Explain what this project does.")
123
+
124
+ for event in stream:
125
+ if isinstance(event, ResponseContentDeltaEvent):
126
+ print(event.delta, end="", flush=True)
127
+
128
+ turn = stream.turn
129
+ print("\ncompleted:", turn.completed)
130
+ ```
131
+
132
+ Add a small tool:
133
+
134
+ ```python
135
+ import subprocess
136
+ from codex_agent import Agent, tool
137
+
138
+ @tool
139
+ def list_changed_files() -> list[str]:
140
+ """Return modified or untracked files in the current git repository."""
141
+ output = subprocess.check_output(["git", "status", "--short"], text=True)
142
+ return [line[3:] for line in output.splitlines() if line.strip()]
143
+
144
+ agent = Agent(session="latest")
145
+ agent.add_tool(list_changed_files)
146
+ agent("What changed locally?")
147
+ ```
148
+
149
+ ## Main ways to use it
150
+
151
+ | Mode | Entry point | Best for |
152
+ | --- | --- | --- |
153
+ | Interactive TUI | `codex-agent` | Daily local assistant usage. |
154
+ | Python SDK | `Agent(...)` | Scripts, notebooks, tests, custom applications. |
155
+ | Headless CLI | `codex-agent run ...` | Automation and shell pipelines. |
156
+ | Persistent server | `codex-agent start server` | Long-lived local service used by UIs or scripts. |
157
+ | Runtime plugins | `~/.codex-agent/plugins/*.py` | Local customization without forking the project. |
158
+
159
+ Useful CLI commands:
160
+
161
+ ```bash
162
+ codex-agent status --json
163
+ codex-agent tools
164
+ codex-agent sessions list
165
+ codex-agent config get
166
+ codex-agent run "Run a quick repository health check."
167
+ git diff -- README.md | codex-agent run --stdin "Review this documentation diff."
168
+ ```
169
+
170
+ ## Built-in capability map
171
+
172
+ | Area | Examples | Purpose |
173
+ | --- | --- | --- |
174
+ | Files/content | `read`, `view`, `write`, `edit` | Strict text reads, broad extraction, exact-string edits. |
175
+ | Shell/Python | `bash`, `python` | Local command execution and persistent Python work. |
176
+ | Context/status | `context_status`, `context_compact` | Inspect and manage the active context window. |
177
+ | Memory/planner | `memory_add`, `planner_create` | Durable semantic memory and persistent named todos. |
178
+ | Scheduler | `scheduler_schedule` | Future turns and post-restart continuation. |
179
+ | Browser/desktop | browser and desktop tools | Persistent Chromium and Linux desktop automation. |
180
+ | Subagents | `subagents_run` | Focused child agents such as the read-only `explorer` profile. |
181
+
182
+ Select built-ins explicitly when you want a smaller agent:
183
+
184
+ ```python
185
+ agent = Agent(
186
+ session="latest",
187
+ builtin_plugins=["files", "content", "bash", "python", "environment", "context"],
188
+ )
189
+ ```
190
+
191
+ `None` loads all built-ins, `[]` loads none, and an explicit list selects plugin module names.
192
+
193
+ ## Documentation
194
+
195
+ The README is intentionally a façade and quick-start guide. Advanced usage lives in `docs/`:
196
+
197
+ - [Python SDK](docs/python-sdk.md): `Agent`, turns, streaming, events, config, and interactive sessions.
198
+ - [Plugins and extensions](docs/plugins.md): tools, providers, commands, runtime plugins, stateful plugins, hooks, events, and stream processors.
199
+ - [CLI and runtime](docs/cli-and-runtime.md): TUI, server, headless CLI, sessions, config, runtime files, and service setup.
200
+ - [Built-in capabilities](docs/built-in-capabilities.md): bundled plugins and common usage patterns.
201
+ - [Safety and trust](docs/safety-and-trust.md): local trust model, runtime plugins, server binding, secrets, and risky actions.
202
+ - [Development](docs/development.md): project layout, tests, build, and release checks.
203
+
204
+ See [CHANGELOG.md](CHANGELOG.md) for release history.
205
+
206
+ ## Safety notes
207
+
208
+ This project lets an AI assistant act on the local machine. That is useful, but risky.
209
+
210
+ Recommended practices:
211
+
212
+ - Avoid running the agent with elevated privileges.
213
+ - Review tools and runtime plugins before enabling autonomous workflows.
214
+ - Keep secrets out of prompts, logs, committed runtime files, and shared session exports.
215
+ - Treat browser, desktop, shell, file-write, and edit operations as real user actions.
216
+ - Keep important runtime plugins under version control.
217
+
218
+ ## License
219
+
220
+ MIT. See [LICENSE](LICENSE).
@@ -0,0 +1,171 @@
1
+ # codex-agent
2
+
3
+ `codex-agent-framework` is a local-first Python framework for building and running tool-using AI agents.
4
+
5
+ Use it as a ready-to-run terminal assistant, or import `Agent` when you want to build your own agentic workflow in Python.
6
+
7
+ > Early alpha: APIs are still evolving and breaking changes are expected while the architecture settles.
8
+
9
+ ## Why codex-agent?
10
+
11
+ codex-agent is meant to be a transparent, hackable local harness for power users and developers:
12
+
13
+ - **Local-first runtime**: sessions, memory, config, plugins, logs, and work files live under your local runtime directory.
14
+ - **Multiple entry points**: TUI, headless CLI, Python SDK, and local FastAPI server.
15
+ - **Plugin-first design**: tools, providers, slash commands, hooks, events, prompt sections, and stream processors are extension points.
16
+ - **Observable agent loop**: turns return structured results and emit events that UIs and integrations can stream.
17
+ - **Built-in practical tools**: files, shell, Python, context, memory, planner, scheduler, browser/desktop automation, and subagents.
18
+
19
+ ## Quick start
20
+
21
+ Install the package:
22
+
23
+ ```bash
24
+ python -m pip install codex-agent-framework
25
+ ```
26
+
27
+ For the recommended local setup, run:
28
+
29
+ ```bash
30
+ codex-agent bootstrap -- -y
31
+ ```
32
+
33
+ `bootstrap` installs desktop/browser/tray dependencies, installs the user services, and starts them. It is currently aimed mostly at Debian-like Linux systems. Use an X11 session for the best desktop automation support; Wayland is fine if you do not use the desktop plugin.
34
+
35
+ Open the assistant:
36
+
37
+ ```bash
38
+ codex-agent
39
+ ```
40
+
41
+ If a local agent server is already running, the TUI connects to it. Otherwise `codex-agent` starts a temporary server for that TUI session and shuts it down when the TUI exits. New sessions are anchored to the directory where you launch `codex-agent`; see [CLI and runtime](docs/cli-and-runtime.md#session-root-and-working-directory).
42
+
43
+ Inside the TUI, start with:
44
+
45
+ ```text
46
+ /help
47
+ /sessions
48
+ /new_session
49
+ /load_session latest
50
+ /compact
51
+ /config
52
+ ```
53
+
54
+ Use `/compact` when a long session needs to reduce its active context. It keeps a backend summary and prunes older raw history from the active session file.
55
+
56
+ ## Python in 30 seconds
57
+
58
+ ```python
59
+ from codex_agent import Agent
60
+
61
+ agent = Agent(session="new")
62
+ turn = agent("Summarize this repository in three practical bullet points.")
63
+
64
+ print(turn.result)
65
+ ```
66
+
67
+ Stream live events when building your own UI or integration:
68
+
69
+ ```python
70
+ from codex_agent import Agent, ResponseContentDeltaEvent
71
+
72
+ agent = Agent(session="new")
73
+ stream = agent.stream("Explain what this project does.")
74
+
75
+ for event in stream:
76
+ if isinstance(event, ResponseContentDeltaEvent):
77
+ print(event.delta, end="", flush=True)
78
+
79
+ turn = stream.turn
80
+ print("\ncompleted:", turn.completed)
81
+ ```
82
+
83
+ Add a small tool:
84
+
85
+ ```python
86
+ import subprocess
87
+ from codex_agent import Agent, tool
88
+
89
+ @tool
90
+ def list_changed_files() -> list[str]:
91
+ """Return modified or untracked files in the current git repository."""
92
+ output = subprocess.check_output(["git", "status", "--short"], text=True)
93
+ return [line[3:] for line in output.splitlines() if line.strip()]
94
+
95
+ agent = Agent(session="latest")
96
+ agent.add_tool(list_changed_files)
97
+ agent("What changed locally?")
98
+ ```
99
+
100
+ ## Main ways to use it
101
+
102
+ | Mode | Entry point | Best for |
103
+ | --- | --- | --- |
104
+ | Interactive TUI | `codex-agent` | Daily local assistant usage. |
105
+ | Python SDK | `Agent(...)` | Scripts, notebooks, tests, custom applications. |
106
+ | Headless CLI | `codex-agent run ...` | Automation and shell pipelines. |
107
+ | Persistent server | `codex-agent start server` | Long-lived local service used by UIs or scripts. |
108
+ | Runtime plugins | `~/.codex-agent/plugins/*.py` | Local customization without forking the project. |
109
+
110
+ Useful CLI commands:
111
+
112
+ ```bash
113
+ codex-agent status --json
114
+ codex-agent tools
115
+ codex-agent sessions list
116
+ codex-agent config get
117
+ codex-agent run "Run a quick repository health check."
118
+ git diff -- README.md | codex-agent run --stdin "Review this documentation diff."
119
+ ```
120
+
121
+ ## Built-in capability map
122
+
123
+ | Area | Examples | Purpose |
124
+ | --- | --- | --- |
125
+ | Files/content | `read`, `view`, `write`, `edit` | Strict text reads, broad extraction, exact-string edits. |
126
+ | Shell/Python | `bash`, `python` | Local command execution and persistent Python work. |
127
+ | Context/status | `context_status`, `context_compact` | Inspect and manage the active context window. |
128
+ | Memory/planner | `memory_add`, `planner_create` | Durable semantic memory and persistent named todos. |
129
+ | Scheduler | `scheduler_schedule` | Future turns and post-restart continuation. |
130
+ | Browser/desktop | browser and desktop tools | Persistent Chromium and Linux desktop automation. |
131
+ | Subagents | `subagents_run` | Focused child agents such as the read-only `explorer` profile. |
132
+
133
+ Select built-ins explicitly when you want a smaller agent:
134
+
135
+ ```python
136
+ agent = Agent(
137
+ session="latest",
138
+ builtin_plugins=["files", "content", "bash", "python", "environment", "context"],
139
+ )
140
+ ```
141
+
142
+ `None` loads all built-ins, `[]` loads none, and an explicit list selects plugin module names.
143
+
144
+ ## Documentation
145
+
146
+ The README is intentionally a façade and quick-start guide. Advanced usage lives in `docs/`:
147
+
148
+ - [Python SDK](docs/python-sdk.md): `Agent`, turns, streaming, events, config, and interactive sessions.
149
+ - [Plugins and extensions](docs/plugins.md): tools, providers, commands, runtime plugins, stateful plugins, hooks, events, and stream processors.
150
+ - [CLI and runtime](docs/cli-and-runtime.md): TUI, server, headless CLI, sessions, config, runtime files, and service setup.
151
+ - [Built-in capabilities](docs/built-in-capabilities.md): bundled plugins and common usage patterns.
152
+ - [Safety and trust](docs/safety-and-trust.md): local trust model, runtime plugins, server binding, secrets, and risky actions.
153
+ - [Development](docs/development.md): project layout, tests, build, and release checks.
154
+
155
+ See [CHANGELOG.md](CHANGELOG.md) for release history.
156
+
157
+ ## Safety notes
158
+
159
+ This project lets an AI assistant act on the local machine. That is useful, but risky.
160
+
161
+ Recommended practices:
162
+
163
+ - Avoid running the agent with elevated privileges.
164
+ - Review tools and runtime plugins before enabling autonomous workflows.
165
+ - Keep secrets out of prompts, logs, committed runtime files, and shared session exports.
166
+ - Treat browser, desktop, shell, file-write, and edit operations as real user actions.
167
+ - Keep important runtime plugins under version control.
168
+
169
+ ## License
170
+
171
+ MIT. See [LICENSE](LICENSE).
@@ -31,10 +31,15 @@ class Agent:
31
31
  **kwargs: Additional keyword arguments to update the agent configuration.
32
32
  """
33
33
  ensure_runtime_dir()
34
+ launch_cwd = os.path.abspath(os.getcwd())
35
+ self.process_launch_cwd = launch_cwd
36
+ explicit_root_dir = kwargs.pop("root_dir", None)
37
+ explicit_cwd = kwargs.pop("cwd", None)
34
38
  self.init_execution_environment()
35
39
  self.config_manager=ConfigManager(self)
36
40
  self.config_manager.load()
37
41
  self.config_manager.update(kwargs, save=False)
42
+ self.init_working_directories(root_dir=explicit_root_dir or launch_cwd, cwd=explicit_cwd)
38
43
  self.config_manager.apply_openai_capability_defaults()
39
44
  self.events=EventBus()
40
45
  self.tools_manager=ToolsManager(self)
@@ -198,6 +203,51 @@ class Agent:
198
203
  "text_content": text_content,
199
204
  }
200
205
 
206
+ def normalize_directory(self, path):
207
+ return os.path.abspath(os.path.expanduser(str(path)))
208
+
209
+ def sync_working_cwd_from_process(self, save_session=False):
210
+ cwd = self.normalize_directory(os.getcwd())
211
+ self.config.cwd = cwd
212
+ session = getattr(self, "session", None)
213
+ if session:
214
+ session.cwd = cwd
215
+ if save_session:
216
+ self.save_session()
217
+ return cwd
218
+
219
+ def set_process_cwd(self, cwd, save_session=False):
220
+ cwd = self.normalize_directory(cwd)
221
+ os.chdir(cwd)
222
+ return self.sync_working_cwd_from_process(save_session=save_session)
223
+
224
+ def init_working_directories(self, root_dir=None, cwd=None):
225
+ root_dir = self.normalize_directory(root_dir or getattr(self, "process_launch_cwd", None) or self.config.root_dir)
226
+ cwd = self.normalize_directory(cwd or root_dir)
227
+ self.config.root_dir = root_dir
228
+ self.set_process_cwd(cwd)
229
+ return self.config.cwd
230
+
231
+ def apply_session_working_directories(self):
232
+ if not self.session:
233
+ return self.config.cwd
234
+ root_dir = getattr(self.session, "root_dir", None) or self.config.root_dir or getattr(self, "process_launch_cwd", None)
235
+ cwd = getattr(self.session, "cwd", None) or root_dir
236
+ self.config.root_dir = self.normalize_directory(root_dir)
237
+ self.session.root_dir = self.config.root_dir
238
+ self.set_process_cwd(cwd)
239
+ self.session.cwd = self.config.cwd
240
+ return self.config.cwd
241
+
242
+ def working_cwd(self):
243
+ return self.sync_working_cwd_from_process(save_session=False)
244
+
245
+ def resolve_path(self, path):
246
+ path = os.path.expanduser(str(path))
247
+ if os.path.isabs(path):
248
+ return os.path.abspath(path)
249
+ return os.path.abspath(os.path.join(self.working_cwd(), path))
250
+
201
251
  def init_workfolder(self):
202
252
  if not os.path.isdir(self.config.workfolder):
203
253
  os.makedirs(self.config.workfolder,exist_ok=True)
@@ -217,8 +267,8 @@ class Agent:
217
267
  def load_session(self, session):
218
268
  return self.sessions_manager.load(session)
219
269
 
220
- def start_new_session(self):
221
- return self.sessions_manager.start_new()
270
+ def start_new_session(self, root_dir=None, cwd=None):
271
+ return self.sessions_manager.start_new(root_dir=root_dir, cwd=cwd)
222
272
 
223
273
  def delete_session(self, session):
224
274
  return self.sessions_manager.delete(session)
@@ -93,7 +93,7 @@ class AgentRuntime(ABC):
93
93
  raise NotImplementedError
94
94
 
95
95
  @abstractmethod
96
- def start_new_session(self):
96
+ def start_new_session(self, root_dir=None, cwd=None):
97
97
  raise NotImplementedError
98
98
 
99
99
  @abstractmethod
@@ -207,8 +207,8 @@ class InProcessAgentRuntime(AgentRuntime):
207
207
  def wakeups(self, include_done=True):
208
208
  return self.agent.scheduler.list(include_done=include_done)
209
209
 
210
- def start_new_session(self):
211
- return self.agent.start_new_session()
210
+ def start_new_session(self, root_dir=None, cwd=None):
211
+ return self.agent.start_new_session(root_dir=root_dir, cwd=cwd)
212
212
 
213
213
  def load_session(self, session_id):
214
214
  return self.agent.load_session(session_id)
@@ -610,8 +610,9 @@ class ProcessAgentRuntime(AgentRuntime):
610
610
  def wakeups(self, include_done=True):
611
611
  return self._cached_call("wakeups", include_done=include_done)
612
612
 
613
- def start_new_session(self):
614
- result = self.call("start_new_session", timeout=self.command_timeout)
613
+ def start_new_session(self, root_dir=None, cwd=None):
614
+ payload = {key: value for key, value in {"root_dir": root_dir, "cwd": cwd}.items() if value is not None}
615
+ result = self.call("start_new_session", payload, timeout=self.command_timeout)
615
616
  self.refresh_cache()
616
617
  return result
617
618
 
@@ -760,7 +761,7 @@ def run_worker_command(agent, name, payload):
760
761
  if name == "wakeups":
761
762
  return agent.scheduler.list(include_done=payload.get("include_done", True))
762
763
  if name == "start_new_session":
763
- return agent.start_new_session()
764
+ return agent.start_new_session(root_dir=payload.get("root_dir"), cwd=payload.get("cwd"))
764
765
  if name == "load_session":
765
766
  return agent.load_session(payload.session_id)
766
767
  if name == "delete_session":
@@ -87,9 +87,9 @@ def sessions():
87
87
 
88
88
 
89
89
  @command
90
- def new_session():
90
+ def new_session(root_dir=None, cwd=None):
91
91
  agent = get_agent()
92
- session = agent.start_new_session()
92
+ session = agent.start_new_session(root_dir=root_dir, cwd=cwd)
93
93
  return f"Created session: {session.session_id}"
94
94
 
95
95
 
@@ -28,7 +28,8 @@ Pass raw shell script text to the tool, not JSON, quotes, or a markdown code fen
28
28
  if not content:
29
29
  return "No bash command provided."
30
30
 
31
- hook = self.agent.run_hook("shell.bash.before", content=content, cwd=os.getcwd())
31
+ cwd = self.agent.working_cwd()
32
+ hook = self.agent.run_hook("shell.bash.before", content=content, cwd=cwd, root_dir=self.agent.config.root_dir)
32
33
  content = hook.payload.content
33
34
  cwd = hook.payload.cwd
34
35
  response = subprocess.run(
@@ -20,7 +20,7 @@ def show(file_or_url: str):
20
20
  """
21
21
  target = str(file_or_url)
22
22
  if not target.startswith(("http://", "https://", "file://")):
23
- target = os.path.abspath(os.path.expanduser(target))
23
+ target = get_agent().resolve_path(target)
24
24
 
25
25
  opened = open_silently(target)
26
26
  if opened:
@@ -5,7 +5,7 @@ from urllib.parse import quote_plus
5
5
  from ...browser import get_browser_controller
6
6
  from ...desktop import DesktopControlError, get_desktop_controller
7
7
  from ...image import ImageMessage, persist_image_url
8
- from ...tool import tool
8
+ from ...tool import get_agent, tool
9
9
  from ...utils import runtime_join
10
10
 
11
11
 
@@ -122,10 +122,18 @@ def observe_source(source):
122
122
  return f"failed: unsupported observe target: {target!r}"
123
123
 
124
124
 
125
+ def resolve_agent_path(path):
126
+ try:
127
+ return get_agent().resolve_path(path)
128
+ except RuntimeError:
129
+ return os.path.abspath(os.path.expanduser(str(path)))
130
+
131
+
125
132
  def observe_path(item):
126
133
  path = item.get("path") or item.get("source")
127
134
  if not isinstance(path, str) or not path:
128
135
  return "failed: path target requires a non-empty 'path'."
136
+ path = resolve_agent_path(path)
129
137
  return validated_image(path, image_name=item.get("image_name"), original_source=path)
130
138
 
131
139
 
@@ -153,8 +161,11 @@ def observe_url(item):
153
161
 
154
162
 
155
163
  def observe_screen(item):
164
+ output_path = item.get("output_path")
165
+ if output_path:
166
+ output_path = resolve_agent_path(output_path)
156
167
  try:
157
- path = get_desktop_controller().capture_screen(item.get("output_path"))
168
+ path = get_desktop_controller().capture_screen(output_path)
158
169
  except DesktopControlError as exc:
159
170
  return f"failed: local screen screenshot failed: {exc}"
160
171
  return validated_image(path, image_name=item.get("image_name", "Screenshot of screen"), original_source="screen")
@@ -162,8 +173,11 @@ def observe_screen(item):
162
173
 
163
174
  def observe_window(item):
164
175
  window_id = item.get("window_id") or item.get("id")
176
+ output_path = item.get("output_path")
177
+ if output_path:
178
+ output_path = resolve_agent_path(output_path)
165
179
  try:
166
- path = get_desktop_controller().capture_window(window_id, item.get("output_path"))
180
+ path = get_desktop_controller().capture_window(window_id, output_path)
167
181
  except DesktopControlError as exc:
168
182
  return f"failed: local window screenshot failed: {exc}"
169
183
  return validated_image(path, image_name=item.get("image_name", f"Screenshot of window {window_id}"), original_source=f"window {window_id}")
@@ -180,6 +194,8 @@ def validated_image(path, image_name=None, original_source=None, url_fallback=Fa
180
194
  def screenshot_page_url(url, item=None):
181
195
  item = item or {}
182
196
  path = item.get("output_path")
197
+ if path:
198
+ path = resolve_agent_path(path)
183
199
  if not path:
184
200
  screenshots_dir = runtime_join("images", "screenshots")
185
201
  os.makedirs(screenshots_dir, exist_ok=True)