bitacora 1.0.0__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.
@@ -0,0 +1,11 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ .venv/
4
+ .pytest_cache/
5
+ .ruff_cache/
6
+ build/
7
+ dist/
8
+ *.egg-info/
9
+ *.spec
10
+ # local state from the pre-1.0 script
11
+ .codex-watch-cache.json
@@ -0,0 +1,17 @@
1
+ # Changelog
2
+
3
+ ## 1.0.0 (2026-10-07)
4
+
5
+ First public release.
6
+
7
+ - Live dashboard for coding agents working in the background, with providers for Codex and Claude Code.
8
+ - Every session with its status, an activity feed (commands, edits, messages, thinking time) and tabs for messages, files, log, result and details.
9
+ - Matches live processes to their sessions by id, or by working directory and start time, including forked Claude Code sessions.
10
+ - Finds a run's log from the parent shell's redirect and remembers result and log paths after the run ends.
11
+ - Codex quota, tokens and context per session.
12
+ - Views (background runs, everything, interactive, live only) and custom views in `config.toml`.
13
+ - Home and setup screen with live counts per view, language, history window, notifications and theme.
14
+ - Notifications when a run finishes, stops or asks a question.
15
+ - Kill with confirmation, open result or log, copy the resume command.
16
+ - English and Spanish interface.
17
+ - `--demo` mode with generated sessions, also used by the tests and the README screenshots.
bitacora-1.0.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Baltazar Andersson
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,166 @@
1
+ Metadata-Version: 2.5
2
+ Name: bitacora
3
+ Version: 1.0.0
4
+ Summary: Live dashboard for coding agents (Codex, Claude Code) working in the background.
5
+ Project-URL: Repository, https://github.com/baltazarandersson/bitacora
6
+ Project-URL: Issues, https://github.com/baltazarandersson/bitacora/issues
7
+ Project-URL: Changelog, https://github.com/baltazarandersson/bitacora/blob/main/CHANGELOG.md
8
+ Author: Baltazar Andersson
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: agents,claude-code,codex,monitor,textual,tui
12
+ Classifier: Development Status :: 5 - Production/Stable
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Operating System :: MacOS
16
+ Classifier: Operating System :: Microsoft :: Windows
17
+ Classifier: Operating System :: POSIX :: Linux
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Topic :: Software Development
23
+ Classifier: Topic :: System :: Monitoring
24
+ Requires-Python: >=3.11
25
+ Requires-Dist: psutil>=5.9
26
+ Requires-Dist: textual>=1.0
27
+ Provides-Extra: dev
28
+ Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
29
+ Requires-Dist: pytest>=8; extra == 'dev'
30
+ Requires-Dist: ruff>=0.6; extra == 'dev'
31
+ Description-Content-Type: text/markdown
32
+
33
+ # Bitácora
34
+
35
+ **English** · [Español](README.es.md)
36
+
37
+ A live dashboard for coding agents working in the background. It supports Codex and Claude Code today.
38
+
39
+ ![Bitácora showing two runs at work, one waiting for an answer and the rest of the day's sessions](docs/screenshot-en.svg)
40
+
41
+ ## Why
42
+
43
+ When you hand work to agents in the background (a `codex exec` in another terminal, a `claude -p` from a script, an orchestrator that launches five runs at once), each one writes its progress to a file you never open. You find out how it went when it ends, or when you remember to look.
44
+
45
+ Bitácora reads those files while they grow. It pairs every agent process with its session and shows what each run is doing, which files it touched, how much context it has left and whether it is waiting for you. It is not a launcher and not a history search tool. It is the panel you keep open while your agents work.
46
+
47
+ ## What it shows
48
+
49
+ - Every session with its status: running, waiting for an answer, your turn, done, aborted or cut off.
50
+ - An activity feed per session: commands with their exit codes, file edits with lines added and removed, messages, and how long the agent thought before each step.
51
+ - Tabs for messages, touched files, the run's log, its result file and the full session details.
52
+ - Tokens, context used and, for Codex, how much of your 5-hour and weekly quota is gone.
53
+ - A notification when a run finishes, stops or asks you something.
54
+ - Actions on the selected run: kill it (it asks first), open its result or log, copy the command that resumes it.
55
+
56
+ ## Install
57
+
58
+ ```bash
59
+ uvx bitacora
60
+ ```
61
+
62
+ Or install it for good with `pipx install bitacora` or `uv tool install bitacora`. You need Python 3.11 or newer.
63
+
64
+ On Windows you can also download `bitacora.exe` from the [latest release](https://github.com/baltazarandersson/bitacora/releases/latest) and run it without Python. It is not code-signed, so SmartScreen will warn you the first time.
65
+
66
+ To try it without any agent installed:
67
+
68
+ ```bash
69
+ uvx bitacora --demo
70
+ ```
71
+
72
+ ## Use
73
+
74
+ ```bash
75
+ bitacora # live sessions plus the last 24 hours
76
+ bitacora --view background # start in a view, skipping the setup screen
77
+ bitacora --live # live sessions only
78
+ bitacora --hours 72 # a longer history window
79
+ bitacora --lang es # Spanish interface
80
+ ```
81
+
82
+ The first time you open it, Bitácora shows its home screen. Each view there comes with the number of sessions it would show from your own machine, so you can tell at a glance what you are choosing. You can come back to that screen anytime with `s` to change the view, language, history window, notifications or theme. On short terminals the header folds into a single line by itself; `h` brings it back.
83
+
84
+ ![The home screen: a lighthouse sweeping its beam over falling code, the views with live counts and the settings](docs/home-en.svg)
85
+
86
+ | Key | Action |
87
+ | --- | --- |
88
+ | `↑` `↓` | Move through sessions |
89
+ | `Enter` / `Esc` | Go into the detail pane / back to the list |
90
+ | `1`–`6` | Activity, Messages, Files, Log, Result, Info |
91
+ | `PgUp` `PgDn`, `Shift+↑↓` | Scroll the detail pane from anywhere |
92
+ | `v` | Full detail: command output, diffs, complete prompts |
93
+ | `a` | Live sessions only |
94
+ | `f` | Pause or resume auto-scroll |
95
+ | `s` | Home: views and preferences |
96
+ | `h` | Fold or unfold the header (or click the `▲ bitácora` strip) |
97
+ | `Ctrl+P` | Command palette: switch view or language, fold the header, toggle filters |
98
+ | `k` | Kill the selected run and its children (asks first) |
99
+ | `o` / `l` | Open the result file / the log |
100
+ | `c` | Copy the command that resumes the session |
101
+ | `t` | Next theme |
102
+ | `q` | Quit |
103
+
104
+ ### Views
105
+
106
+ | View | Shows |
107
+ | --- | --- |
108
+ | Background runs | `codex exec`, `claude -p` and SDK runs |
109
+ | Everything | Every session from every agent |
110
+ | Interactive | Desktop apps, IDEs and terminal chats |
111
+ | Live only | Whatever is running right now |
112
+
113
+ You can add your own in `config.toml`. `bitacora --paths` prints where that file lives.
114
+
115
+ ```toml
116
+ lang = "en" # en, es, or leave it out to follow the system
117
+ hours = 24 # history window
118
+ notify = true # toast and bell when a run finishes, stops or asks
119
+
120
+ [views.codex-bg]
121
+ name = "Codex in the background"
122
+ providers = ["codex"] # codex, claude
123
+ kind = "background" # background, interactive or all
124
+ live_only = false
125
+ ```
126
+
127
+ What you save in the setup screen takes precedence over `config.toml`, and command line flags take precedence over both.
128
+
129
+ ## How it works
130
+
131
+ Bitácora only reads files the agents already write.
132
+
133
+ - **Codex**: rollouts in `~/.codex/sessions` (or `$CODEX_HOME`), thread names from `session_index.jsonl`, and the `codex exec` / `codex` processes with their flags (`-m`, `-c`, `-C`, `-s`, `-o`, `resume <id>`).
134
+ - **Claude Code**: transcripts in `~/.claude/projects` (or `$CLAUDE_CONFIG_DIR`) and the `claude` processes with `--resume`, `--session-id`, `--model`, `-p`.
135
+
136
+ A live process is matched to its session by id when the command line has one, and otherwise by working directory and start time. The log comes from a `> run.log` redirect in the parent shell's command line. Bitácora remembers each session's label, result and log paths in its own state file, so a finished run still shows them.
137
+
138
+ ## Privacy
139
+
140
+ Everything stays on your machine. Bitácora makes no network requests and never writes to the agents' files. The only thing it can do to an agent is kill it, and only after you confirm. Its state file holds session labels and file paths; `bitacora --paths` shows where.
141
+
142
+ ## Limits
143
+
144
+ - Neither format is documented, and both change between versions. This release was tested with Codex CLI 0.161 and Claude Code 2.1.
145
+ - Windows is where it gets the most use. Linux and macOS pass the test suite in CI, but have seen less real use.
146
+ - Reasoning is stored encrypted or not at all, so the activity feed shows how long the agent thought rather than what it thought (Codex includes summaries if `model_reasoning_summary` is on).
147
+ - Claude Code does not record its context window, so for Claude sessions Bitácora shows context in tokens instead of a percentage.
148
+ - Subagent sessions are not grouped under their parent yet.
149
+
150
+ ## Development
151
+
152
+ ```bash
153
+ git clone https://github.com/baltazarandersson/bitacora
154
+ cd bitacora
155
+ python -m venv .venv && .venv/bin/pip install -e ".[dev]" # .venv\Scripts\pip on Windows
156
+ pytest
157
+ ruff check .
158
+ python -m bitacora --demo
159
+ python scripts/screenshot.py en # regenerates docs/*.svg from the demo
160
+ ```
161
+
162
+ Adding an agent means writing a provider in `bitacora/providers/`: where its sessions live, how its processes look and how to turn its records into events. The demo generator in `bitacora/demo.py` doubles as the test fixture.
163
+
164
+ ## License
165
+
166
+ MIT. Bitácora is an independent project, not affiliated with OpenAI or Anthropic.
@@ -0,0 +1,134 @@
1
+ # Bitácora
2
+
3
+ [English](README.md) · **Español**
4
+
5
+ Un panel en vivo para los agentes de código que trabajan en segundo plano. Hoy funciona con Codex y Claude Code.
6
+
7
+ ![Bitácora con dos corridas trabajando, una esperando respuesta y el resto de las sesiones del día](docs/screenshot-es.svg)
8
+
9
+ ## Por qué
10
+
11
+ Cuando le delegas trabajo a agentes en segundo plano (un `codex exec` en otra terminal, un `claude -p` desde un script, un orquestador que lanza cinco corridas a la vez), cada uno va dejando su progreso en un archivo que nunca abres. Te enteras de cómo fue cuando termina, o cuando te acuerdas de mirar.
12
+
13
+ Bitácora lee esos archivos mientras crecen. Empareja cada proceso con su sesión y muestra qué está haciendo cada corrida, qué archivos tocó, cuánto contexto le queda y si está esperando algo de ti. No lanza agentes ni busca en tu historial: es el panel que dejas abierto mientras tus agentes trabajan.
14
+
15
+ ## Qué muestra
16
+
17
+ - Cada sesión con su estado: corriendo, esperando respuesta, te toca, terminada, abortada o cortada.
18
+ - La actividad de cada sesión: comandos con su código de salida, archivos editados con líneas agregadas y quitadas, mensajes, y cuánto pensó el agente antes de cada paso.
19
+ - Pestañas para los mensajes, los archivos tocados, el log de la corrida, su archivo de resultado y todos los datos de la sesión.
20
+ - Tokens, contexto usado y, en Codex, cuánto llevas gastado de la cuota de 5 horas y de la semanal.
21
+ - Un aviso cuando una corrida termina, se corta o te pregunta algo.
22
+ - Acciones sobre la corrida seleccionada: matarla (te pide confirmación), abrir su resultado o su log, copiar el comando que la retoma.
23
+
24
+ ## Instalación
25
+
26
+ ```bash
27
+ uvx bitacora
28
+ ```
29
+
30
+ Si prefieres dejarlo instalado: `pipx install bitacora` o `uv tool install bitacora`. Necesitas Python 3.11 o más nuevo.
31
+
32
+ En Windows también puedes descargar `bitacora.exe` desde la [última release](https://github.com/baltazarandersson/bitacora/releases/latest) y usarlo sin Python. No está firmado, así que SmartScreen te va a avisar la primera vez.
33
+
34
+ Para probarlo sin tener ningún agente instalado:
35
+
36
+ ```bash
37
+ uvx bitacora --demo
38
+ ```
39
+
40
+ ## Uso
41
+
42
+ ```bash
43
+ bitacora # sesiones vivas y las últimas 24 horas
44
+ bitacora --view background # arranca en una vista y saltea la pantalla de inicio
45
+ bitacora --live # solo sesiones vivas
46
+ bitacora --hours 72 # una ventana de historial más larga
47
+ bitacora --lang en # interfaz en inglés
48
+ ```
49
+
50
+ La primera vez, Bitácora abre su pantalla de inicio. Cada vista aparece con la cantidad de sesiones que mostraría con los datos de tu propia máquina, así sabes qué estás eligiendo antes de elegirlo. Puedes volver a esa pantalla cuando quieras con `s` para cambiar la vista, el idioma, la ventana de historial, los avisos o el tema. En terminales bajas la cabecera se pliega sola en una línea; `h` la despliega.
51
+
52
+ ![La pantalla de inicio: un faro que barre con su luz sobre código que cae, las vistas con sus conteos y la configuración](docs/home-es.svg)
53
+
54
+ | Tecla | Acción |
55
+ | --- | --- |
56
+ | `↑` `↓` | Moverse entre sesiones |
57
+ | `Enter` / `Esc` | Entrar al panel de detalle / volver a la lista |
58
+ | `1`–`6` | Actividad, Mensajes, Archivos, Log, Resultado, Info |
59
+ | `PgUp` `PgDn`, `Shift+↑↓` | Desplazar el detalle desde cualquier lado |
60
+ | `v` | Detalle completo: salida de comandos, diffs, prompts enteros |
61
+ | `a` | Solo sesiones vivas |
62
+ | `f` | Pausar o reanudar el auto-scroll |
63
+ | `s` | Inicio: vistas y preferencias |
64
+ | `h` | Plegar o desplegar la cabecera (o un clic en la franja `▲ bitácora`) |
65
+ | `Ctrl+P` | Paleta de comandos: cambiar de vista o idioma, plegar la cabecera, alternar filtros |
66
+ | `k` | Matar la corrida seleccionada y sus hijos (pide confirmación) |
67
+ | `o` / `l` | Abrir el archivo de resultado / el log |
68
+ | `c` | Copiar el comando que retoma la sesión |
69
+ | `t` | Siguiente tema |
70
+ | `q` | Salir |
71
+
72
+ ### Vistas
73
+
74
+ | Vista | Muestra |
75
+ | --- | --- |
76
+ | En segundo plano | `codex exec`, `claude -p` y corridas del SDK |
77
+ | Todo | Todas las sesiones de todos los agentes |
78
+ | Interactivas | Apps de escritorio, IDEs y chats en terminal |
79
+ | Solo vivas | Lo que está corriendo ahora |
80
+
81
+ Puedes sumar las tuyas en `config.toml`. `bitacora --paths` te dice dónde está ese archivo.
82
+
83
+ ```toml
84
+ lang = "es" # en, es, o no lo pongas para seguir al sistema
85
+ hours = 24 # ventana de historial
86
+ notify = true # aviso y campana cuando una corrida termina, se corta o pregunta
87
+
88
+ [views.codex-bg]
89
+ name = "Codex en segundo plano"
90
+ providers = ["codex"] # codex, claude
91
+ kind = "background" # background, interactive o all
92
+ live_only = false
93
+ ```
94
+
95
+ Lo que guardas en la pantalla de configuración tiene prioridad sobre `config.toml`, y los flags de la línea de comandos tienen prioridad sobre los dos.
96
+
97
+ ## Cómo funciona
98
+
99
+ Bitácora solo lee archivos que los agentes ya escriben.
100
+
101
+ - **Codex**: los rollouts en `~/.codex/sessions` (o `$CODEX_HOME`), los nombres de los threads en `session_index.jsonl`, y los procesos `codex exec` / `codex` con sus flags (`-m`, `-c`, `-C`, `-s`, `-o`, `resume <id>`).
102
+ - **Claude Code**: las transcripciones en `~/.claude/projects` (o `$CLAUDE_CONFIG_DIR`) y los procesos `claude` con `--resume`, `--session-id`, `--model`, `-p`.
103
+
104
+ Cada proceso vivo se empareja con su sesión por id cuando la línea de comandos lo trae, y si no, por carpeta de trabajo y hora de inicio. El log sale de una redirección `> run.log` en la línea de comandos del shell padre. Bitácora guarda el nombre, el resultado y el log de cada sesión en su propio archivo de estado, así una corrida terminada los sigue mostrando.
105
+
106
+ ## Privacidad
107
+
108
+ Todo queda en tu máquina. Bitácora no hace pedidos a la red y nunca escribe en los archivos de los agentes. Lo único que le puede hacer a un agente es matarlo, y solo después de que confirmes. Su archivo de estado guarda nombres de sesiones y rutas de archivos; `bitacora --paths` te muestra dónde.
109
+
110
+ ## Límites
111
+
112
+ - Ninguno de los dos formatos está documentado, y los dos cambian entre versiones. Esta versión se probó con Codex CLI 0.161 y Claude Code 2.1.
113
+ - Donde más se usa es en Windows. En Linux y macOS pasa los tests en CI, pero tiene menos uso real.
114
+ - El razonamiento se guarda cifrado o no se guarda, así que la actividad muestra cuánto pensó el agente y no qué pensó (Codex incluye resúmenes si `model_reasoning_summary` está activo).
115
+ - Claude Code no registra su ventana de contexto, así que en sus sesiones Bitácora muestra el contexto en tokens y no en porcentaje.
116
+ - Las sesiones de subagentes todavía no se agrupan bajo su sesión madre.
117
+
118
+ ## Desarrollo
119
+
120
+ ```bash
121
+ git clone https://github.com/baltazarandersson/bitacora
122
+ cd bitacora
123
+ python -m venv .venv && .venv/bin/pip install -e ".[dev]" # .venv\Scripts\pip en Windows
124
+ pytest
125
+ ruff check .
126
+ python -m bitacora --demo
127
+ python scripts/screenshot.py es # regenera docs/*.svg a partir de la demo
128
+ ```
129
+
130
+ Sumar un agente es escribir un provider en `bitacora/providers/`: dónde guarda sus sesiones, cómo se ven sus procesos y cómo convertir sus registros en eventos. El generador de la demo en `bitacora/demo.py` también sirve como fixture de los tests.
131
+
132
+ ## Licencia
133
+
134
+ MIT. Bitácora es un proyecto independiente, sin relación con OpenAI ni Anthropic.
@@ -0,0 +1,134 @@
1
+ # Bitácora
2
+
3
+ **English** · [Español](README.es.md)
4
+
5
+ A live dashboard for coding agents working in the background. It supports Codex and Claude Code today.
6
+
7
+ ![Bitácora showing two runs at work, one waiting for an answer and the rest of the day's sessions](docs/screenshot-en.svg)
8
+
9
+ ## Why
10
+
11
+ When you hand work to agents in the background (a `codex exec` in another terminal, a `claude -p` from a script, an orchestrator that launches five runs at once), each one writes its progress to a file you never open. You find out how it went when it ends, or when you remember to look.
12
+
13
+ Bitácora reads those files while they grow. It pairs every agent process with its session and shows what each run is doing, which files it touched, how much context it has left and whether it is waiting for you. It is not a launcher and not a history search tool. It is the panel you keep open while your agents work.
14
+
15
+ ## What it shows
16
+
17
+ - Every session with its status: running, waiting for an answer, your turn, done, aborted or cut off.
18
+ - An activity feed per session: commands with their exit codes, file edits with lines added and removed, messages, and how long the agent thought before each step.
19
+ - Tabs for messages, touched files, the run's log, its result file and the full session details.
20
+ - Tokens, context used and, for Codex, how much of your 5-hour and weekly quota is gone.
21
+ - A notification when a run finishes, stops or asks you something.
22
+ - Actions on the selected run: kill it (it asks first), open its result or log, copy the command that resumes it.
23
+
24
+ ## Install
25
+
26
+ ```bash
27
+ uvx bitacora
28
+ ```
29
+
30
+ Or install it for good with `pipx install bitacora` or `uv tool install bitacora`. You need Python 3.11 or newer.
31
+
32
+ On Windows you can also download `bitacora.exe` from the [latest release](https://github.com/baltazarandersson/bitacora/releases/latest) and run it without Python. It is not code-signed, so SmartScreen will warn you the first time.
33
+
34
+ To try it without any agent installed:
35
+
36
+ ```bash
37
+ uvx bitacora --demo
38
+ ```
39
+
40
+ ## Use
41
+
42
+ ```bash
43
+ bitacora # live sessions plus the last 24 hours
44
+ bitacora --view background # start in a view, skipping the setup screen
45
+ bitacora --live # live sessions only
46
+ bitacora --hours 72 # a longer history window
47
+ bitacora --lang es # Spanish interface
48
+ ```
49
+
50
+ The first time you open it, Bitácora shows its home screen. Each view there comes with the number of sessions it would show from your own machine, so you can tell at a glance what you are choosing. You can come back to that screen anytime with `s` to change the view, language, history window, notifications or theme. On short terminals the header folds into a single line by itself; `h` brings it back.
51
+
52
+ ![The home screen: a lighthouse sweeping its beam over falling code, the views with live counts and the settings](docs/home-en.svg)
53
+
54
+ | Key | Action |
55
+ | --- | --- |
56
+ | `↑` `↓` | Move through sessions |
57
+ | `Enter` / `Esc` | Go into the detail pane / back to the list |
58
+ | `1`–`6` | Activity, Messages, Files, Log, Result, Info |
59
+ | `PgUp` `PgDn`, `Shift+↑↓` | Scroll the detail pane from anywhere |
60
+ | `v` | Full detail: command output, diffs, complete prompts |
61
+ | `a` | Live sessions only |
62
+ | `f` | Pause or resume auto-scroll |
63
+ | `s` | Home: views and preferences |
64
+ | `h` | Fold or unfold the header (or click the `▲ bitácora` strip) |
65
+ | `Ctrl+P` | Command palette: switch view or language, fold the header, toggle filters |
66
+ | `k` | Kill the selected run and its children (asks first) |
67
+ | `o` / `l` | Open the result file / the log |
68
+ | `c` | Copy the command that resumes the session |
69
+ | `t` | Next theme |
70
+ | `q` | Quit |
71
+
72
+ ### Views
73
+
74
+ | View | Shows |
75
+ | --- | --- |
76
+ | Background runs | `codex exec`, `claude -p` and SDK runs |
77
+ | Everything | Every session from every agent |
78
+ | Interactive | Desktop apps, IDEs and terminal chats |
79
+ | Live only | Whatever is running right now |
80
+
81
+ You can add your own in `config.toml`. `bitacora --paths` prints where that file lives.
82
+
83
+ ```toml
84
+ lang = "en" # en, es, or leave it out to follow the system
85
+ hours = 24 # history window
86
+ notify = true # toast and bell when a run finishes, stops or asks
87
+
88
+ [views.codex-bg]
89
+ name = "Codex in the background"
90
+ providers = ["codex"] # codex, claude
91
+ kind = "background" # background, interactive or all
92
+ live_only = false
93
+ ```
94
+
95
+ What you save in the setup screen takes precedence over `config.toml`, and command line flags take precedence over both.
96
+
97
+ ## How it works
98
+
99
+ Bitácora only reads files the agents already write.
100
+
101
+ - **Codex**: rollouts in `~/.codex/sessions` (or `$CODEX_HOME`), thread names from `session_index.jsonl`, and the `codex exec` / `codex` processes with their flags (`-m`, `-c`, `-C`, `-s`, `-o`, `resume <id>`).
102
+ - **Claude Code**: transcripts in `~/.claude/projects` (or `$CLAUDE_CONFIG_DIR`) and the `claude` processes with `--resume`, `--session-id`, `--model`, `-p`.
103
+
104
+ A live process is matched to its session by id when the command line has one, and otherwise by working directory and start time. The log comes from a `> run.log` redirect in the parent shell's command line. Bitácora remembers each session's label, result and log paths in its own state file, so a finished run still shows them.
105
+
106
+ ## Privacy
107
+
108
+ Everything stays on your machine. Bitácora makes no network requests and never writes to the agents' files. The only thing it can do to an agent is kill it, and only after you confirm. Its state file holds session labels and file paths; `bitacora --paths` shows where.
109
+
110
+ ## Limits
111
+
112
+ - Neither format is documented, and both change between versions. This release was tested with Codex CLI 0.161 and Claude Code 2.1.
113
+ - Windows is where it gets the most use. Linux and macOS pass the test suite in CI, but have seen less real use.
114
+ - Reasoning is stored encrypted or not at all, so the activity feed shows how long the agent thought rather than what it thought (Codex includes summaries if `model_reasoning_summary` is on).
115
+ - Claude Code does not record its context window, so for Claude sessions Bitácora shows context in tokens instead of a percentage.
116
+ - Subagent sessions are not grouped under their parent yet.
117
+
118
+ ## Development
119
+
120
+ ```bash
121
+ git clone https://github.com/baltazarandersson/bitacora
122
+ cd bitacora
123
+ python -m venv .venv && .venv/bin/pip install -e ".[dev]" # .venv\Scripts\pip on Windows
124
+ pytest
125
+ ruff check .
126
+ python -m bitacora --demo
127
+ python scripts/screenshot.py en # regenerates docs/*.svg from the demo
128
+ ```
129
+
130
+ Adding an agent means writing a provider in `bitacora/providers/`: where its sessions live, how its processes look and how to turn its records into events. The demo generator in `bitacora/demo.py` doubles as the test fixture.
131
+
132
+ ## License
133
+
134
+ MIT. Bitácora is an independent project, not affiliated with OpenAI or Anthropic.
@@ -0,0 +1,3 @@
1
+ """Bitácora: a live dashboard for coding agents working in the background."""
2
+
3
+ __version__ = "1.0.0"
@@ -0,0 +1,3 @@
1
+ from bitacora.cli import main
2
+
3
+ main()
@@ -0,0 +1,78 @@
1
+ """Command line entry point."""
2
+ from __future__ import annotations
3
+
4
+ import argparse
5
+ import json
6
+ import os
7
+ import sys
8
+ import tempfile
9
+ from pathlib import Path
10
+
11
+ from bitacora import __version__, i18n
12
+ from bitacora.store import State, config_path, load_config, state_path
13
+ from bitacora.views import BUILTIN
14
+
15
+
16
+ def build_parser() -> argparse.ArgumentParser:
17
+ ap = argparse.ArgumentParser(
18
+ prog="bitacora",
19
+ description="Live dashboard for coding agents (Codex, Claude Code) working in the background.")
20
+ ap.add_argument("--view", help="start in this view: " + ", ".join(v.id for v in BUILTIN)
21
+ + " or one from config.toml (skips the first-run picker)")
22
+ ap.add_argument("--live", action="store_true", help="show live sessions only")
23
+ ap.add_argument("--hours", type=float, help="history window in hours (default 24)")
24
+ ap.add_argument("--lang", choices=i18n.LANGS, help="interface language (default: system)")
25
+ ap.add_argument("--demo", action="store_true", help="run on generated sample sessions")
26
+ ap.add_argument("--paths", action="store_true", help="print where config and state live, and exit")
27
+ ap.add_argument("--version", action="version", version=f"bitacora {__version__}")
28
+ return ap
29
+
30
+
31
+ def main(argv: list[str] | None = None) -> None:
32
+ args = build_parser().parse_args(argv)
33
+ if args.paths:
34
+ print(json.dumps({"config": str(config_path()), "state": str(state_path())}, indent=1))
35
+ return
36
+
37
+ animator = None
38
+ if args.demo:
39
+ from bitacora import demo
40
+ root = Path(tempfile.mkdtemp(prefix="bitacora-demo-"))
41
+ data = demo.generate(root)
42
+ os.environ["CODEX_HOME"] = str(data["codex_home"])
43
+ os.environ["CLAUDE_CONFIG_DIR"] = str(data["claude_home"])
44
+ os.environ["BITACORA_HOME"] = str(root / "home")
45
+ seed = State()
46
+ for key, entry in data["state"].items():
47
+ seed.remember(key, entry)
48
+ seed.save()
49
+ animator = demo.Animator(data["live"])
50
+
51
+ from bitacora.providers import all_providers
52
+ from bitacora.ui.app import create_app
53
+
54
+ if animator:
55
+ animator.start()
56
+ view, collector = args.view, None
57
+ try:
58
+ while True:
59
+ # Precedence: command line, then what you saved in setup, then config.toml.
60
+ config, state = load_config(), State()
61
+ lang = args.lang or state.get("lang") or config.lang or "auto"
62
+ config.hours = args.hours or state.get("hours") or config.hours
63
+ config.notify = state.get("notify", config.notify)
64
+ i18n.set_lang(None if lang == "auto" else lang)
65
+ app = create_app(all_providers(), config, state, view=view, live_only=args.live,
66
+ scan_procs=not args.demo, lang=args.lang or state.get("lang") or "auto",
67
+ collector=collector)
68
+ if app.run() != "relaunch":
69
+ break
70
+ collector = app.collector # keep what was already read; the new app only relabels
71
+ view = None # a relaunch after setup starts in the view just saved
72
+ finally:
73
+ if animator:
74
+ animator.stop.set()
75
+
76
+
77
+ if __name__ == "__main__":
78
+ sys.exit(main())
@@ -0,0 +1,95 @@
1
+ """Joins live processes with their session files, plus recent history, across providers."""
2
+ from __future__ import annotations
3
+
4
+ import time
5
+ from pathlib import Path
6
+
7
+ from bitacora import procs
8
+ from bitacora.model import ProcInfo, Run, Session
9
+ from bitacora.providers import Provider
10
+ from bitacora.store import State
11
+ from bitacora.util import label_from_out, label_from_prompt
12
+
13
+
14
+ class Collector:
15
+ def __init__(self, providers: list[Provider], state: State, hours: float, scan_procs: bool = True):
16
+ self.providers = providers
17
+ self.state = state
18
+ self.hours = hours
19
+ self.scan_procs = scan_procs
20
+ self.sessions: dict[Path, Session] = {}
21
+ self.pid_map: dict[tuple[str, int], Path] = {}
22
+ self.log_seen: dict[tuple[str, int], str | None] = {}
23
+ self.quotas: dict[str, dict] = {}
24
+
25
+ def _session(self, prov: Provider, path: Path) -> Session:
26
+ s = self.sessions.get(path)
27
+ if s is None:
28
+ s = self.sessions[path] = prov.session_cls(path)
29
+ s.update()
30
+ title = prov.title(s)
31
+ if title:
32
+ s.title = title
33
+ return s
34
+
35
+ def _live_run(self, prov: Provider, pi: ProcInfo, claimed: set[Path]) -> Run:
36
+ key = (prov.name, pi.pid)
37
+ path = self.pid_map.get(key)
38
+ if path is None or not path.exists():
39
+ path = prov.match(pi, claimed)
40
+ s = None
41
+ if path:
42
+ self.pid_map[key] = path
43
+ claimed.add(path)
44
+ s = self._session(prov, path)
45
+ sid = s.session_id if s else None
46
+ skey = f"{prov.name}:{sid}" if sid else ""
47
+ cached = self.state.session(skey) if skey else {}
48
+ out = pi.out or cached.get("out")
49
+ if pi.log is None:
50
+ # The redirect is fixed at launch and walking parent processes is slow: look once per process.
51
+ if key not in self.log_seen:
52
+ self.log_seen[key] = cached.get("log") or procs.find_log(pi.pid, out, prov.marker)
53
+ pi.log = self.log_seen[key]
54
+ label = (label_from_out(out) or (s and s.title) or cached.get("label")
55
+ or (s and label_from_prompt(s.first_prompt)) or f"pid {pi.pid}")
56
+ if skey:
57
+ self.state.remember(skey, {"label": label, "out": out, "log": pi.log, "cmdline": pi.cmdline})
58
+ return Run(skey or f"{prov.name}:pid{pi.pid}", prov.name, s, pi, label, out, pi.log)
59
+
60
+ def collect(self) -> list[Run]:
61
+ snap = procs.snapshot() if self.scan_procs else []
62
+ runs: dict[str, Run] = {}
63
+ since = time.time() - self.hours * 3600
64
+ seen: set[Path] = set()
65
+ alive: set[tuple[str, int]] = set()
66
+ for prov in self.providers:
67
+ if not prov.available():
68
+ continue
69
+ claimed: set[Path] = set()
70
+ for pi in sorted(prov.procs(snap), key=lambda x: x.create):
71
+ alive.add((prov.name, pi.pid))
72
+ run = self._live_run(prov, pi, claimed)
73
+ runs[run.key] = run
74
+ seen |= claimed
75
+ for f in prov.history(since):
76
+ if f in claimed:
77
+ continue
78
+ s = self._session(prov, f)
79
+ seen.add(f)
80
+ key = f"{prov.name}:{s.session_id or f}"
81
+ if key in runs:
82
+ continue
83
+ cached = self.state.session(key)
84
+ label = (label_from_out(cached.get("out")) or s.title or cached.get("label")
85
+ or label_from_prompt(s.first_prompt) or f.stem[-12:])
86
+ runs[key] = Run(key, prov.name, s, None, label, cached.get("out"), cached.get("log"))
87
+ mine = [s for p, s in self.sessions.items() if s.provider == prov.name and p in seen]
88
+ quota = prov.quota(mine)
89
+ if quota:
90
+ self.quotas[prov.name] = quota
91
+ self.pid_map = {k: v for k, v in self.pid_map.items() if k in alive}
92
+ self.log_seen = {k: v for k, v in self.log_seen.items() if k in alive}
93
+ self.sessions = {p: s for p, s in self.sessions.items() if p in seen}
94
+ self.state.save()
95
+ return sorted(runs.values(), key=lambda r: (not r.live, -(r.start or 0)))