
Security News
GitHub to Block pull_request_target Workflows by Default Starting December 2
GitHub is tightening GitHub Actions security with new restrictions on privileged pull request workflows. Here's what changes and how maintainers are affected.
chronicle-context
Advanced tools
Record your screen and system events for a set time, build a knowledge graph, and serve it to any agent over MCP.

A recording open on its knowledge graph, using the synthetic sample workday that chronicle demo loads. No real screen data is shown.
Chronicle records your screen and system events on your machine, writes context files and workflows from them, and builds them into agent harnesses that plug into any AI over MCP. Full documentation is at aniketxdey.github.io/chronicle.
Agents usually start every task knowing nothing about your computer. They don't know which ticket you were on, which file you had open, or what you looked up ten minutes ago. So you end up pasting context in by hand. Chronicle keeps that memory locally and lets the agent ask for it:
export.ts, that PR 882 is waiting on review, and what the export spec in Notion said.Everything is stored in one local folder (~/.chronicle), with no account and no telemetry. The only data that leaves the machine goes to model providers you give a key to (see Privacy).
Requires Python 3.10+. macOS is the main platform; Linux (X11) and Windows support is best effort.
uv tool install "chronicle-context[graph]" # or: pipx install "chronicle-context[graph]"
chronicle demo # load a synthetic workday, so you can try it without recording
chronicle context "finish the Acme export" # print what an agent would receive
chronicle mcp install cursor # or claude-desktop, claude-code, codex, vscode, gemini-cli, ...
chronicle context prints the same Markdown that the get_context MCP tool returns. On the sample workday it begins like this (trimmed):
# Computer context (Chronicle)
Task: finish the Acme export
## What you were doing
- 15:34-15:56 writing Acme Export spec · amount_usd (22m) [topic 1]
- 16:28-16:48 coding export.ts · amount_usd (20m) [topic 2]
- 16:50-17:02 coding Checks passed · Merge (12m) [topic 3]
## On screen now
- Chrome · Checks · PR 882 at Sun 16:50 (frame 18)
- URL: https://github.com/northwind/billing/actions
- Visible text: ... Merge is waiting on Priya's second review. Acme export is still due Friday.
## Knowledge graph (all)
- [topic] Acme export (`topic:acme-export`, 1h58m, frames 18, 16, 13)
- [pr] PR 882 (`pr:882`, 2h42m, frames 18, 17, 16)
- [file] export.ts (`file:export.ts`, 1h48m, frames 17, 11, 6)
- [person] Maya Chen (`person:maya-chen`, 2h28m, frames 16, 14, 12)
To record your own work, run chronicle doctor to check permissions, then chronicle record 30m or chronicle serve and use the UI at http://127.0.0.1:3030.
Permissions and platform tools
xdotool and xprop. For screenshots install one of grim, gnome-screenshot, scrot, or ImageMagick import. Add xclip or wl-paste for the clipboard and xprintidle for idle time.brew install tesseract or apt install tesseract-ocr.The only required dependencies are FastAPI and uvicorn. The graph extra adds scikit-learn and scipy for better duplicate merging, and llm adds the OpenAI SDK and python-dotenv.
Record. A session runs for a set duration (90s, 30m, 2h) or until stopped. Every 5 seconds by default, the recorder samples the front app and window, the browser URL and tab title, and a screenshot. It also logs the system events app_switch, window_focus, url_change, clipboard, idle_start/idle_end, and session_start/session_stop. Screen text comes from the macOS Accessibility tree, and from tesseract OCR on the screenshot when an app exposes no text. Keystrokes are never recorded. Password managers, System Settings, and private browsing windows are skipped, and emails, API keys, JWTs, and card numbers are redacted before anything is written.
Build the graph. Each session gets its own graph shard. The shard is extended while recording and rebuilt once when the session ends, and frames captured outside a session go into hourly shards. The all-history graph is a SQL aggregation over the shards in which older shards count less (72-hour half-life by default). That keeps it focused on current work, and deleting a session just drops its shard.
BILL-142), PRs, code identifiers, people, projects, customers, meetings, sessions, and tasks. Topics are keyphrases such as "Acme export", scored by frequency, spread, casing, position, and dwell time. Tasks are activity segmented by topic.has_window, visited, on_site, shows, searched, about, co_occurs, switched_to and then (workflow transitions), spoke_in, discussed, copied, typed (text pushed through POST /add), and captured.Every node and edge records the time spent on it and the frames it came from, so an agent can cite its evidence. If an OpenAI key is available, a model also refines each recording when it ends (see LLM refinement).
Serve. get_context(task) returns a context pack with these parts:
Agents then drill down with query_graph, get_entity, search_history, and get_frame, which can return the screenshot itself.
These need uv on the PATH. Each runs uvx chronicle-context mcp and tells the model to call get_context before acting.
claude plugin marketplace add aniketxdey/chronicle, then claude plugin install chronicle@chronicle.gemini extensions install https://github.com/aniketxdey/chronicle.io.github.aniketxdey/chronicle.chronicle mcp install <client> merges the server into the client's config and keeps a .chronicle-backup copy of the old file. chronicle mcp config <client> prints the snippet instead, and chronicle mcp clients lists them all.
| Client | Command | Config written |
|---|---|---|
| Claude Desktop | chronicle mcp install claude-desktop | claude_desktop_config.json → mcpServers |
| Claude Code | chronicle mcp install claude-code | runs claude mcp add --scope user chronicle -- … |
| Cursor | chronicle mcp install cursor | ~/.cursor/mcp.json |
| VS Code (Copilot agent mode) | chronicle mcp install vscode | user mcp.json → servers |
| Windsurf | chronicle mcp install windsurf | ~/.codeium/windsurf/mcp_config.json |
| OpenAI Codex CLI | chronicle mcp install codex | ~/.codex/config.toml → [mcp_servers.chronicle] |
| Gemini CLI | chronicle mcp install gemini-cli | ~/.gemini/settings.json |
| Cline, LM Studio | chronicle mcp install cline / lm-studio | their mcpServers JSON |
| Zed, Continue, Goose | chronicle mcp config zed / continue / goose | paste the snippet |
For any other client:
{ "mcpServers": { "chronicle": { "command": "chronicle", "args": ["mcp"] } } }
A stdio server can record on its own. Only one Chronicle process captures at a time: whichever holds ~/.chronicle/capture.lock. So an agent can call start_recording without chronicle serve running. Pass --no-record to turn this off.
chronicle serve exposes MCP at POST /mcp and supports protocol versions 2025-06-18, 2025-03-26, and 2024-11-05. Hosted agents need a public HTTPS URL, so put it behind a tunnel and set a token:
export CHRONICLE_TOKEN=$(openssl rand -hex 16)
export CHRONICLE_PUBLIC_URL=https://<your-tunnel-host>
chronicle serve &
cloudflared tunnel --url http://127.0.0.1:3030 # or ngrok, tailscale funnel
# MCP URL: $CHRONICLE_PUBLIC_URL/mcp/$CHRONICLE_TOKEN, or /mcp with "Authorization: Bearer $CHRONICLE_TOKEN"
With a token set, every route except the UI shell and /health requires it. Open the UI once with ?token=… and it remembers the token. Requests with a non-local Origin header are rejected.
/mcp/<token> URL with no authentication. The search and fetch tools return the shapes that connectors and deep research expect.tools=[{"type": "mcp", "server_label": "chronicle", "server_url": URL, "require_approval": "never"}]. See examples/openai_responses.py.mcp-client-2025-04-04): mcp_servers=[{"type": "url", "url": URL, "name": "chronicle"}], alongside the computer-use tool. See examples/anthropic_computer_use.py.google-genai): pass an MCP ClientSession connected to chronicle mcp as a tool. chronicle mcp config gemini-api prints the snippet.chronicle mcp config http prints a curl call.Provider model names and beta flags change often, so treat these snippets as starting points and check the provider's MCP docs.
| Tool | What it does |
|---|---|
get_context | Context pack for a task: current screen, recent activity and events, transitions, relevant subgraph, cited frames. An optional preset (such as coding or job-applications) focuses it on that work and opens it with instructions to follow |
search_history | Full-text search over screen text, events, transcripts, and memories |
query_graph / get_entity / graph_summary | Find entities, walk their neighbors with evidence frames, and get counts and top transitions |
list_tasks | Timeline of tasks, segmented from activity and grouped by topic |
get_frame | One frame with nearby events and audio; include_image=true attaches the screenshot |
list_harnesses / get_harness / read_harness_file / search_harness_graph | Use a harness: its AGENTS.md, its files, and its graph engine |
get_context_file / get_workflow / get_graph | Use one context file, workflow, or graph on its own |
start_recording / stop_recording / list_sessions | Let the agent record a demonstration for a set duration |
rebuild_graph / activity_summary / list_meetings | Maintenance and summaries |
tune_graph | Run the LLM refinement pass on a scope |
graph_review / graph_apply | Let the connected agent curate the graph itself, with no separate model or API key |
search / fetch | ChatGPT connector and deep-research interface |
Resources: chronicle://context/current, chronicle://graph/summary, chronicle://sessions, and the templates chronicle://harness/{id}, chronicle://context-file/{id}, chronicle://workflow/{id}, chronicle://context/session/{id}, and chronicle://frame/{id}.
Prompts: use_my_computer_context(task), and learn_from_recording(session_id), which turns a recorded demonstration into steps an agent can repeat:
chronicle record 5m --label "file an expense report" # do the task once
chronicle context --session 1 # check what the agent will see
Then ask the agent: "Use the learn_from_recording prompt for session 1 and do it again for this receipt."
chronicle serve runs the UI at http://127.0.0.1:3030:
The REST API is documented at http://127.0.0.1:3030/docs. The most useful routes:
| Route | Purpose |
|---|---|
POST /sessions {duration, label} | Start a recording |
GET /context?task=&format=markdown | The get_context pack |
GET /graph, GET /graph/node?id= | Graph and single-node lookups |
GET /contexts/file?preset=… | A context file, plus which model wrote it |
POST /contexts/compose | Write one context file from the recordings, earlier contexts, and workflows you pick |
POST /workflows/generate | Have the model write workflows from the recordings and context files you pick |
POST /harnesses | Build a harness from recordings, context files, and workflows |
POST /harnesses/{id}/chat | Edit a harness by chat with your model |
GET /harnesses/{id}/export | Download a harness as a zip or one Markdown file |
GET /graph/download/{recording,context,workflow}/{id} | One knowledge graph as JSON, text, GraphML, or Cypher |
POST /clients/{id}/install / uninstall | Connect or disconnect a local client |
GET /sessions/{id}/stats | Live storage, frame, event, page, and app totals for a recording |
GET /contexts/export?format=md|json|graphml|cypher | Exports |
POST /add | Push frames, events, or transcripts from your own capture, such as a Whisper audio pipeline |
chronicle serve [--host --port] web UI, REST API, and HTTP MCP
chronicle record <duration> [--label --interval --detach]
chronicle stop [id] · chronicle sessions
chronicle graph build|show|find|node|export [--session N] (build --full re-extracts every shard)
chronicle graph tasks [--session N --since "2h ago" --json]
chronicle graph merges [--session N --threshold --json] (near-duplicate nodes the build merges)
chronicle graph tune [--session N --rounds 2 --force --reset]
chronicle context [task] [--minutes N --session N --json]
chronicle mcp [stdio|clients|config <client>|install <client> [--path --dry-run]]
chronicle search <q> · chronicle ask <question> · chronicle status · chronicle doctor · chronicle demo
| Variable | Default | Meaning |
|---|---|---|
CHRONICLE_HOME | ~/.chronicle | Database, screenshots, and lock file |
CHRONICLE_TOKEN | unset | Require this token on the HTTP API and MCP |
CHRONICLE_PUBLIC_URL | http://127.0.0.1:3030 | Base URL for links and remote client snippets |
CHRONICLE_DEMO=1 | off | Load the sample workday into an empty database on start |
CHRONICLE_DISABLE_CAPTURE=1 | off | Never record from this process |
CHRONICLE_HALF_LIFE_HOURS | 72 | Decay half-life for the all-history graph; 0 or off disables it |
CHRONICLE_LLM | unset (automatic) | openai, anthropic, gemini, openrouter, local, or off. Unset uses the first provider with a key. Settings › Model beats it, except off, which always keeps models off |
CHRONICLE_LLM_MODEL | gpt-4.1-mini / claude-sonnet-5-5 | Model for graph refinement, context files, and Ask. Required for local |
OPENAI_API_KEY / OPENAI_BASE_URL | unset / OpenAI | Credentials and endpoint for the openai provider |
ANTHROPIC_API_KEY | unset | Credentials for the anthropic provider |
GEMINI_API_KEY / OPENROUTER_API_KEY | unset | Credentials for the gemini and openrouter providers |
CHRONICLE_LLM_BASE_URL | http://localhost:11434/v1 | OpenAI-compatible endpoint for the local provider |
Capture interval, idle threshold, screenshots, OCR, clipboard, redaction, and retention are settings, edited in the UI or through POST /settings. Two settings mirror environment variables: graph_half_life_hours overrides CHRONICLE_HALF_LIFE_HOURS, while CHRONICLE_LLM takes precedence over llm_provider.
The heuristic graph knows apps, pages, tickets, files, and identifiers, but it can't tell that "Crusoe" is a company or that a page is a job posting. When a model is set up, it names the graph's nodes, works out what you did from system events and pages, and writes the context files. Set one up under Settings › Model with an OpenAI or Anthropic key, or point it at a local server such as Ollama or LM Studio. Without one, Chronicle runs fully offline: the graph stays heuristic and context files are assembled from the recording directly.
uv tool install "chronicle-context[graph,llm]"
echo "OPENAI_API_KEY=sk-..." >> ~/.chronicle/.env
chronicle graph tune --session 1 # runs automatically when a recording ends
chronicle graph show --session 1 # activities and typed relations are listed first
The key can also come from the environment or a .env in the current directory. A .env never overrides variables that are already set. Settings › Model or CHRONICLE_LLM=off turns the model off. GET /llm/status reports the provider and model in use and the last error.
Graph patches. The model reads the heaviest nodes along with their evidence: window titles, URLs and search queries, redacted screen text, and dwell time. It replies through strict function calls: add_entity, retype_node, rename_node, merge_nodes, add_relation, add_trait, record_action, drop_action, set_activity, and drop_node. A final pass over every named node merges what separate batches named twice. Actions must cite real frames and carry a status (completed, worked on, discussed, or viewed), because a screen shows state, not what you did. Actions and the system events behind them are kept inside each node, so the graph shows named things and the detail stays one click away. add_relation supports is_a, part_of, works_on, competes_with, located_in, researching, mentions, listed_in, uses, and related_to.
--rounds passes (default 2) and stops early when nothing new is proposed.kg_llm_patches and replayed after every rebuild, so refinement survives graph build. --reset removes them.source: "llm", and relations carry a confidence and an evidence quote. get_context lists activities first, then relations such as Crusoe —is_a→ company.Context files. For each of the eight presets, the model writes a document with the sections that kind of work needs and an "Open threads" list, citing frames. The evidence it was given is appended under "Recorded evidence".
Caching and failures.
--force.last_llm_error and never stop a recording. A failed context file falls back to the offline version.Other providers can be added with chronicle.llm.register(name, factory). A provider implements call_tools(system, user, tools) -> [{"name", "arguments"}] and complete(system, user) -> str.
Recordings, screenshots, and the graph stay in CHRONICLE_HOME. Data leaves the machine in three cases:
chronicle ask and the Ask box send the matching history to the provider you configure in Settings.PRIVACY.md has the details.
git clone https://github.com/aniketxdey/chronicle && cd chronicle
uv pip install -e ".[dev,graph,llm]"
pytest
python examples/stdio_client.py "finish the Acme export"
npx @modelcontextprotocol/inspector --cli chronicle mcp --method tools/list
| Module | Role |
|---|---|
chronicle/probe.py | Reads the machine: windows, URLs, screenshots, Accessibility text, OCR |
capture.py, sessions.py | The recorder and timed sessions |
graph.py | Shard building, aggregation, and decay |
tuner.py, llm.py | LLM patch pass and providers |
context.py, contexts.py | Context packs and context files |
mcp_server.py, clients.py | JSON-RPC core, stdio transport, and per-client setup |
main.py, web/ | HTTP server and UI |
Releases are described in docs/PUBLISHING.md. The OSWorld benchmark harness is in bench/, and bench/PROTOCOL.md describes the evaluation. It hasn't been run yet, so there are no results.
MIT
FAQs
Record your screen and system events for a set time, build a knowledge graph, and serve it to any agent over MCP.
The pypi package chronicle-context receives a total of 232 weekly downloads. As such, chronicle-context popularity was classified as not popular.
We found that chronicle-context demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Security News
GitHub is tightening GitHub Actions security with new restrictions on privileged pull request workflows. Here's what changes and how maintainers are affected.

Security News
/Application Security
A practical guide to securing GitHub Actions against supply chain attacks, covering malicious pull requests, credential theft, dependency risks, and release pipelines.

Security News
Composer 2.11 adds dependency cooldowns, joining package managers that delay new releases to reduce supply chain risks while allowing urgent security updates.