Skip to main content

Agent Diary

Remember what you did with an AI. Automatically when a Claude Code session ends, or on one command in Codex, Agent Diary records what you asked for and what changed.

CI License: MIT Python 3.8+ Core Dependencies: 0

English | 한국어

This is a community project. It is not an official Anthropic or OpenAI project.

Agent Diary demo

Here to read the code? Architecture covers the idempotency key and its cache invalidation, a retry policy that branches on cause, schema versioning, and what partial failure means. The postmortem is how one schema PATCH emptied six properties across 497 rows.

1. Why

Work done with an AI lives in a chat window, and chat windows close. Two days later there is no way back to why a file was changed the way it was, and when a weekly review or a status report comes due you are working from memory. A commit log keeps the result; it does not keep what you asked for or what was tried on the way there.

Agent Diary captures that context at the moment a session ends. There is no habit to build.

One finished session appends an entry like this.

### ⏰ 14:30:15 | 📁 `my-app`

**🏷️ Categories:** `feature` `test`

**📋 Task Requests:**
  1. Add JWT authentication to login
  2. Write the tests as well

**📄 Files Created:**
  - `src/auth/jwt_handler.py`
  - `tests/test_auth.py`

**✏️ Files Modified:**
  - `src/api/routes.py`

**🔀 Git:**
  - 🌿 Branch: `feat/jwt-auth`
  - Commit: `a1b2c3d` feat: verify tokens and cover login

**📊 Code Stats:** +145 / -12 lines (5 files)

**⚡ Key Commands:**
  - `export API_KEY=****`
  - `pytest -q`

**📝 Work Summary:**
  - Added JWT verification middleware and covered the login failure path

**🔒 1 secrets masked**

Categories are inferred from the work. Branch, commits and diff stats are read from the repository. Anything that looks like a secret — the API_KEY above — is masked before the file is written.

What makes it different

  • It is automatic. In Claude Code a Stop Hook picks up the end of a session. You never have to decide to record something.
  • Zero core dependencies. Standard library only. requests is added only if you use the Notion integration.
  • Local files. Plain Markdown, so it greps, it opens in Obsidian, and it outlives any service.
  • It scales to a team. Push to a Notion work-log database when you need to, or export to Slack, Discord and GitHub.
pip install agent-diary
agent-diary init
agent-diary backfill      # optional: import the sessions you already have

Nothing else is required. Every Claude Code session from then on lands in ~/working-diary/YYYY-MM-DD.md.

Claude Code has been keeping transcripts on disk all along, so backfill gives you a diary of work you already did rather than an empty directory. On the machine this was built on it turned 79 past sessions into 21 days of entries. Running it twice changes nothing — sessions already in the diary are skipped.

This project was claude-diary, then working-diary, and is now agent-diary. If you installed it under an older name, the working-diary and claude-diary commands still work.

The internal Python package is still claude_diary. install writes python -m claude_diary.hook into the user's settings.json, so renaming it would stop an existing Stop Hook silently. A distribution name that differs from the import name is ordinary in Python.

Supported Agents

Agent Auto diary Manual Markdown Notion work log Apply/refresh
Claude Code Stop Hook /diary /diary-notion agent-diary install --force
Codex None $diary $diary-notion agent-diary install --force --codex-only

Package installation is shared, but agent setup is different. Use --codex-only for Codex-only setup without modifying Claude Code settings. --codex remains as a compatibility option that also refreshes the Claude Code hook and slash commands.

Storage Paths

Automatic diaries are appended to daily files.

~/working-diary/
  2026-03-15.md
  2026-03-16.md
  .session_counts.json
  weekly/
    W11_2026-03-09.md

Manual diaries are stored separately by date and project.

~/working-diary/manual/
  2026-04-29/
    my-project/
      2026-04-29.md

2. Usage

Follow the sequence for the target workflow.

Goal Command sequence
Claude Code Markdown auto/manual diary pip install agent-diary -> agent-diary init -> agent-diary install --force
Claude Code with Notion work log pip install "agent-diary[notion]" -> agent-diary init -> agent-diary install --force -> agent-diary diary-notion init -> agent-diary diary-notion ensure
Codex Markdown manual diary pip install agent-diary -> agent-diary init --codex-only -> agent-diary install --force --codex-only -> open a new Codex session
Codex with Notion work log pip install "agent-diary[notion]" -> agent-diary init --codex-only -> agent-diary install --force --codex-only -> agent-diary diary-notion init -> agent-diary diary-notion ensure -> open a new Codex session

2-1. Package Install And Basic Setup

pip install:

pip install agent-diary
agent-diary init

With Notion support:

pip install "agent-diary[notion]"
agent-diary init

Claude Code plugin installation is a separate distribution path for Claude Code plugin marketplace users.

# Run inside Claude Code
/plugin marketplace add https://github.com/solzip/agent-diary
/plugin install agent-diary

The plugin distributes Claude Code hook settings. The agent-diary CLI comes from the Python package, so Python package installation and agent-diary init are still required.

Install from source:

git clone https://github.com/solzip/agent-diary.git
cd agent-diary
pip install -e .
agent-diary init

Install from source with Notion support:

pip install -e ".[notion]"

agent-diary init creates the config file and diary directory, and it also registers the Claude Code Stop Hook. If you only use Codex, run agent-diary init --codex-only to avoid modifying Claude Code settings.

Run the agent-specific apply command below to refresh Claude Code slash commands or Codex skills.

2-2. Claude Code Usage

Claude Code supports automatic diaries when sessions end and manual diaries during a session.

Apply or refresh Claude Code setup:

agent-diary install --force

Automatic diary flow:

Claude Code session ends
  -> Stop Hook runs
  -> transcript is parsed
  -> ~/working-diary/YYYY-MM-DD.md

Manual Markdown diary:

/diary

Notion work log:

/diary-notion

/diary finds the Claude Code transcript for the current project and records it through the agent-diary write core. /diary-notion creates task-row JSON from the session and passes it to agent-diary diary-notion push.

2-3. Codex Usage

Codex does not use an automatic hook. It records only when the user invokes a skill.

Apply or refresh Codex setup:

agent-diary install --force --codex-only

--codex-only installs only the Codex skills under ~/.codex/skills and does not modify Claude Code hooks or slash commands. --codex remains as a compatibility option that also refreshes the Claude Code setup.

Manual Markdown diary:

$diary

Notion work log:

$diary-notion

$diary and $diary-notion create JSON from the current Codex conversation and tool activity, then call the same core CLI. Already-running Codex sessions keep the skills loaded at startup. Refreshed skills are applied in a new Codex session.

2-4. First Notion Setup

Notion work logs require the optional requests dependency.

pip install "agent-diary[notion]"

For source installs:

pip install -e ".[notion]"

Setup steps:

  1. Create a Notion integration at https://www.notion.so/my-integrations and copy the token.
  2. Create a Notion root page, for example Agent Diary.
  3. Share the root page with the integration.
  4. Save the configuration.
agent-diary diary-notion init

diary-notion init stores the Notion token and root page ID you enter in local config. If you later set CLAUDE_DIARY_NOTION_TOKEN or CLAUDE_DIARY_NOTION_ROOT_PAGE_ID, those environment variables override the saved config values.

  1. Ensure the yearly Entries database, schema, and views.
agent-diary diary-notion ensure
  1. Run /diary-notion or $diary-notion from an agent session.

2-5. Notion Push Behavior

agent-diary diary-notion push --input .diary-notion-<id>.json
agent-diary diary-notion push --input .diary-notion-<id>.json --force
agent-diary diary-notion push --input .diary-notion-<id>.json --dry-run
  • Default push skips rows already recorded with the same Session ID + Task Index.
  • --force archives prior rows for the session and pushes again.
  • --dry-run prints the rows and page bodies that would be created without writing to Notion. Add --preview-file <path> to save the same rendering as Markdown.
  • If a Task Group already has recorded sessions, the title gets an (N차) ordinal. The first session of a group is left alone.
  • --dry-run reads from Notion to resolve that ordinal — a query, nothing more. Without credentials, or before that year's database exists, it renders without the ordinal and says so at the top of the output. A preview never creates a page or a database.
  • If any task fails, the command exits with code 1 and preserves the input JSON.
  • Fully successful pushes and already-skipped pushes exit with code 0.

2-6. What A Push Leaves On Disk (Run Artifacts)

Every push writes a record of the run under the current working directory, by default. --dry-run writes it too.

<cwd>/.agent-diary/runs/<YYYYMMDD-HHMMSS-session>/
  input.json        the original task JSON
  git-diff.patch    the working tree diff at push time
  preview.md        the rendered Notion body
  manifest.json     the files above with sha256, plus a push result summary

Notion is the destination, not the record. If a push half-fails, or a row is later edited by hand, this local copy is the only way back to what was actually submitted.

git-diff.patch contains your uncommitted code. Keep it out of your repository:

.agent-diary/runs/

To relocate or disable it:

agent-diary diary-notion push --input <json> --artifact-dir build/diary-runs
agent-diary diary-notion push --input <json> --no-artifacts

2-7. Review Queue

Review is a judgement a person makes after the fact, so no stage of the recording pipeline declares work reviewed on its own. Push files every new row as Needs Review, and only this command's --apply promotes a row to Reviewed.

agent-diary diary-notion review              # list rows awaiting review (read-only)
agent-diary diary-notion review --apply      # set Reviewed + Last Reviewed=today
agent-diary diary-notion review --year 2026

Without --apply nothing is written, matching the ensure --dry-run / ensure pattern.

2-8. Notion Sub-Items

Expandable task hierarchy uses Notion native Sub-items. Enable it once in the Notion UI.

  1. Open the yearly Entries database.
  2. Open the top-right ... menu and enable Sub-items.
  3. Run agent-diary diary-notion ensure again.

Rows are still recorded if Sub-items are not enabled. Only visual nesting is missing, and push prints a hint.

3. Logic

This section covers what flows where, in what order. Why it is built that way — the idempotency key, the retry policy, schema versioning, partial-failure handling — is in Architecture.

3-1. Core Logic

The core handles actual recording independently of the agent.

input
  -> transcript or agent-authored JSON
  -> cwd, session_id, task metadata

core processing
  -> parser
  -> Git enrichment
  -> category inference
  -> secret scan
  -> formatter
  -> writer or Notion exporter
  -> audit/index/export retry

Key modules:

Area File Role
CLI entry src/claude_diary/cli/__init__.py Routes the agent-diary command and its working-diary / claude-diary aliases
Automatic diary core src/claude_diary/core.py Claude Code Stop Hook diary pipeline
Manual diary core src/claude_diary/cli/write.py Handles /diary, $diary, and agent-diary write
Notion push src/claude_diary/cli/notion_push/ Pushes task JSON as Notion rows (split into validate/properties/relations/artifacts)
Notion schema/view src/claude_diary/cli/notion_ensure.py Ensures schema v8, 5 core views and 5 operating views
Notion review queue src/claude_diary/cli/notion_review.py Lists Needs Review rows; --apply records Reviewed
Formatter src/claude_diary/formatter.py Creates Markdown entries and Notion page bodies

3-2. Claude Code Logic

Automatic diary:

Claude Code Stop Hook
  -> src/claude_diary/hook.py
  -> core.process_session(session_id, transcript_path, cwd)
  -> ~/working-diary/YYYY-MM-DD.md

Manual diary:

/diary
  -> agent-diary write
  -> find Claude transcript for the current cwd
  -> append to manual diary path

/diary-notion
  -> agent creates task JSON
  -> agent-diary diary-notion push --input <json>
  -> push rows to Notion Entries DB

agent-diary install --force refreshes:

  • ~/.claude/settings.json Stop Hook
  • ~/.claude/commands/diary.md
  • ~/.claude/commands/diary-notion.md

3-3. Codex Logic

Codex has no Stop Hook. Global skills call the core CLI.

$diary
  -> Codex writes current session content to .diary-<id>.json
  -> agent-diary write --input .diary-<id>.json
  -> append to manual diary path

$diary-notion
  -> Codex splits the session into tasks
  -> writes .diary-notion-<id>.json
  -> agent-diary diary-notion push --input .diary-notion-<id>.json
  -> push rows to Notion Entries DB

agent-diary install --force --codex-only refreshes:

  • ~/.codex/skills/diary/SKILL.md
  • ~/.codex/skills/diary-notion/SKILL.md

4. CLI

Core commands:

agent-diary init
agent-diary init --codex-only
agent-diary install --force
agent-diary install --force --codex
agent-diary install --force --codex-only
agent-diary uninstall
agent-diary uninstall --codex
agent-diary uninstall --codex-only

agent-diary write
agent-diary write --input .diary-<id>.json

agent-diary backfill
agent-diary backfill --dry-run
agent-diary backfill --since 2026-07-01
agent-diary backfill --limit 20
agent-diary backfill --transcripts /path/to/projects

agent-diary doctor
agent-diary doctor --notion

agent-diary report
agent-diary report --days 14
agent-diary report --month 2026-07
agent-diary report --from 2026-07-01 --to 2026-07-15
agent-diary report --project my-app --output july.md
agent-diary report --month 2026-07 --detail
agent-diary report --month 2026-07 --json

agent-diary diary-notion init
agent-diary diary-notion ensure
agent-diary diary-notion ensure --dry-run
agent-diary diary-notion ensure --year 2026

agent-diary diary-notion push --input .diary-notion-<id>.json
agent-diary diary-notion push --input .diary-notion-<id>.json --force
agent-diary diary-notion push --input .diary-notion-<id>.json --dry-run
agent-diary diary-notion push --input .diary-notion-<id>.json --preview-file preview.md
agent-diary diary-notion push --input .diary-notion-<id>.json --artifact-dir build/diary-runs
agent-diary diary-notion push --input .diary-notion-<id>.json --no-artifacts

agent-diary diary-notion ops
agent-diary diary-notion ops --stale-days 14
agent-diary diary-notion ops --json

agent-diary diary-notion review
agent-diary diary-notion review --apply

agent-diary notion push --input .diary-notion-<id>.json

Search and maintenance commands:

agent-diary search "keyword"
agent-diary filter --project my-app
agent-diary trace src/main.py
agent-diary stats
agent-diary weekly
agent-diary audit
agent-diary audit --verify
agent-diary config
agent-diary config --set lang=en
agent-diary migrate
agent-diary reindex
agent-diary delete --last

Extension commands:

agent-diary config --add-exporter slack
agent-diary config --add-exporter discord
agent-diary config --add-exporter obsidian
agent-diary config --add-exporter github
agent-diary dashboard
agent-diary dashboard --serve --port 8787
agent-diary team stats
agent-diary team weekly
agent-diary team monthly --month 2026-06
agent-diary team init --repo <url> --name <name>
agent-diary team add-member --name <name> --role member

The legacy CLI remains supported.

agent-diary write
agent-diary diary-notion ensure

5. Configuration

The config file is stored at the OS-specific user config path under claude-diary/config.json. If you configure exporters such as Notion, Slack, or Discord, API tokens, webhook URLs, and root page IDs are stored in this local config. CLI output masks long token and webhook values.

These variables fall into two groups whose precedence runs in opposite directions. Read the last column first.

Environment variable Description Default Precedence
CLAUDE_DIARY_LANG Diary language, ko or en ko config.json wins
CLAUDE_DIARY_DIR Automatic diary path ~/working-diary config.json wins
CLAUDE_DIARY_MANUAL_DIR Manual diary path ~/working-diary/manual config.json wins
CLAUDE_DIARY_TZ_OFFSET UTC offset 9 config.json wins
CLAUDE_DIARY_NOTION_TOKEN Notion token - env wins
CLAUDE_DIARY_NOTION_ROOT_PAGE_ID Notion root page ID - env wins
CLAUDE_DIARY_SKIP 1, true, or yes skips Claude Code Stop Hook auto diary - env only

The first four merge as config.json > environment > defaults. So if you have ever run init, the key is already written to the config and setting the environment variable has no effect. To move the diary path, edit config.json rather than exporting a variable.

Reports for a period

search finds an entry and stats counts things. report writes one document for a stretch of work, for a standup, a monthly summary, an invoice, or evidence of what a period consisted of.

agent-diary report                                  # the last 7 days
agent-diary report --month 2026-07 --project my-app
agent-diary report --from 2026-07-01 --to 2026-07-15 --output july.md
# Work report — 2026-07-01 ~ 2026-07-31

640 session(s) · 16 day(s) · 1 project(s) · +21871 / -11431 lines · 11272 file(s) · 2305 commit(s)

`docs` 197 · `bugfix` 177 · `test` 169 · `feature` 88

## my-app — 640 session(s)

### 2026-07-01
- Added JWT verification middleware and covered the login failure path
- 

It draws the session list from the search index and the prose from the diary, joined on session id, so a report filtered to one project does not inherit another project's sentences from the same day.

The work summary is preferred over the requests you typed — the summary is the synthesised record, the requests are raw input. --detail includes both. When a day has no summary the requests are used and the report says so.

What gets recorded, and how to limit it

Your prompts are stored as written. That is the point of the tool, and it is also the thing to think about before running it at work: a prompt routinely contains a client name, an internal URL, or business context you would not put in a file you forget about.

Three controls, all off by default.

Skip one session — nothing is written, no config change:

CLAUDE_DIARY_SKIP=1 claude

Skip a project permanently. A bare name matches the directory name; anything with a separator is treated as a path and covers everything beneath it:

{
  "skip_projects": [
    "personal-notes",        // any directory with this name
    "~/clients",             // this directory and everything under it
    "C:\\work\\acme"
  ]
}

The path form exists because a name alone cannot tell ~/work/acme from ~/personal/acme, and because listing every client repository by hand is the sort of chore that gets skipped until the session you most wanted excluded.

Redact more than the built-in patterns. Secrets are masked before anything is written — 11+ patterns for API keys, tokens and private keys. Add your own regexes for names that are not secrets but are still yours:

{
  "security": {
    "additional_secret_patterns": [
      "acme-corp",
      "internal\\.example\\.com",
      "PROJ-\\d{4}"
    ]
  }
}

Matches become **** in the diary, in Notion, and in every exporter, because masking happens before the entry is formatted.

agent-diary doctor reports how many of each rule are active, so "what is this recording" has an answer you can check rather than remember.

Gitmoji on commit lines

Off by default. Turn it on in config.json and each commit line gains the gitmoji for its Conventional Commit type:

{ "formatting": { "gitmoji": true } }
-  - Commit: `a1b2c3d` feat: verify tokens and cover login
+  - Commit: `a1b2c3d` ✨ feat: verify tokens and cover login

A commit with no recognised type is left as it is, and one that already starts with an emoji is not given a second.

It applies to commit lines only, not to the category tags. Three gitmoji — 📝, ⚡ and 🔒 — already mean Work Summary, Key Commands and secrets-masked in an entry, and decorating categories would give the same glyph two meanings on one screen.

The two Notion credentials are the exception and override the config, so a token need not be written to a file in CI or when moving between workspaces.

If PowerShell output shows broken Korean or emoji characters, switch the current session output encoding to UTF-8.

[Console]::OutputEncoding = [System.Text.UTF8Encoding]::new()
$OutputEncoding = [System.Text.UTF8Encoding]::new()

6. Features

  • Automatic category inference
  • Git branch, commit, and diff stat recording
  • Secret scanning and masking
  • Search index
  • Notion work log: agent-diary diary-notion init -> agent-diary diary-notion ensure
  • Notion operations report: agent-diary diary-notion ops for blocked/review/next action/stale/work days/today-plan candidates/parent status signals
  • Review queue: agent-diary diary-notion review. Push always files as Needs Review; only --apply promotes a row to Reviewed
  • Run artifacts: every push preserves input.json, git-diff.patch, preview.md and manifest.json locally, each sha256-stamped
  • Automatic (N차) ordinals for sessions continuing the same Task Group, with no extra column
  • A day's rows read in the order the work was done (Date ties broken by Task Index)
  • Slack, Discord, Obsidian, GitHub exporters: agent-diary config --add-exporter <name>
  • HTML dashboard: agent-diary dashboard or agent-diary dashboard --serve --port 8787
  • Audit log and source checksum verification
  • Team mode: agent-diary team init --repo <url> --name <name>

7. Troubleshooting

Symptom Check
/diary or /diary-notion does not use the latest instructions Run agent-diary install --force to refresh the hook and slash commands
$diary or $diary-notion does not use the latest instructions Run agent-diary install --force --codex-only, then open a new Codex session
Notion push reports an auth error Check the integration token, root page ID, and page sharing
Notion task hierarchy is not nested Enable Sub-items once in the Notion Entries database UI
Re-push might duplicate rows Default push skips the same Session ID + Task Index; use --force to rewrite
A .agent-diary/ directory appeared in my project That is the push run record. Add .agent-diary/runs/ to .gitignore, or disable it with --no-artifacts (see 2-6)
Entries stopped appearing and I do not know why Run agent-diary doctor. It checks that the hook is registered, that the module it names still resolves, and how long it has been since the last entry
I used to get .codefleet/runs/ That was the old default, named after a separate project. New projects use .agent-diary/runs/; an existing .codefleet/runs/ keeps being used so your history does not split
I want to drop the (N차) suffix from titles It counts prior sessions of the same Task Group. Leave task_group empty and no suffix is added
PowerShell text is garbled Apply the UTF-8 output setting above

8. Development

pip install -e ".[dev,notion]"
python -m pytest -q
python -m ruff check .
python -m mypy

Run bare, mypy checks only the modules listed in pyproject.toml. That list is the annotated core, and CI keeps it green. Annotating a new module means adding it to the list — being on the list is a commitment to stay clean.

CI runs it on the Python 3.12 job only, because current mypy will not run under this project's 3.8 floor. The annotations themselves are written for 3.8.

9. Roadmap

This README focuses on currently usable functionality. Detailed design and planning artifacts live under docs/.

Area Status
Available Claude Code Stop Hook, Codex skills, Markdown diaries, Notion task row push, schema v8 / view ensure, ops operations report, review queue, push run artifacts
In progress Notion schema reduction (#12), dry-run ordinals (#10), Schema Version string fix (#11)
Next Windows install/output experience, Notion sub-item guidance
Under review SQLite search index, Cursor/Windsurf/VS Code integration

10. Documentation

If you are deciding whether the code is worth reading, start with these two.

  • Architecture — the idempotency model, the retry and error-taxonomy policy, cache invalidation, schema versioning, what partial failure means, and why the core has no dependencies
  • Postmortem: ensure emptied six properties across 497 rows — symptom, measurement against production, root cause, fix, regression tests, and why it went unseen for two months

Detailed design notes:

11. License

MIT

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

agent_diary-4.8.2.tar.gz (245.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

agent_diary-4.8.2-py3-none-any.whl (149.4 kB view details)

Uploaded Python 3

File details

Details for the file agent_diary-4.8.2.tar.gz.

File metadata

  • Download URL: agent_diary-4.8.2.tar.gz
  • Upload date:
  • Size: 245.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for agent_diary-4.8.2.tar.gz
Algorithm Hash digest
SHA256 d5e16acc3df985ebeb71ea3f30ad032391ce5bfb8dbdd2c2ac538e7c8e6d2b2c
MD5 4d96a0fe3e2cb5eb70b87f5f2ee7ed0f
BLAKE2b-256 f91259e2cf7ac0d368825b299cacc8fa791f8c826eeb188b80f142e3ccec91ee

See more details on using hashes here.

Provenance

The following attestation bundles were made for agent_diary-4.8.2.tar.gz:

Publisher: release.yml on solzip/agent-diary

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file agent_diary-4.8.2-py3-none-any.whl.

File metadata

  • Download URL: agent_diary-4.8.2-py3-none-any.whl
  • Upload date:
  • Size: 149.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for agent_diary-4.8.2-py3-none-any.whl
Algorithm Hash digest
SHA256 fc85c103641b89b1c222911817e388414bb22f56c6a820adb8e3b0f8d2186624
MD5 cc3c5d977d3e211c879039cdf58827ac
BLAKE2b-256 5085536742793fa21a4fafee00b71f5efbcb322b8e222fde4d2a2060e3322ece

See more details on using hashes here.

Provenance

The following attestation bundles were made for agent_diary-4.8.2-py3-none-any.whl:

Publisher: release.yml on solzip/agent-diary

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page