Part of the DEVIN ecosystem
Track: Control · Nature: product
For: Operations, Security engineers
Interface: CLI / Automation
Path: Operations · step 3/4 — afterdevin-backup, beforedevin-metrics
Path: Security engineers · step 3/3 — afterdevin-redact
devin-janitor
Unofficial community project. Not affiliated with, endorsed by, or sponsored by Cognition AI. "Devin" is a trademark of Cognition AI.
Linux · Personal Windows · Corporate Windows
Part of the awesome-devin ecosystem: the curated hub for the devin-* tools.
The lifecycle janitor for Devin sessions: export first, classify in tiers,
delete only the safe tiers, retry locked files, vacuum only when Devin is
closed — so sessions.db and acp-messages/ never bloat with
empty/automation noise again.
The problem
Daily Devin Desktop use accumulates session pollution: empty sessions,
automation/eval noise (classification probes, judge calls, JSON payloads),
one-shot heartbeat/mailbox cycles, and duplicates of the same task. On a real
install this noise was ~55% of all sessions — drowning out actual work in the
session list and growing sessions.db + User/acp-messages/ without bound.
Devin ships no built-in lifecycle management, and deleting rows blindly is
dangerous: locked files, open databases and ambiguous sessions all need
handling.
Prior art
Generic SQLite cleanup scripts and browser-history cleaners exist for many
tools, but none know Devin's layout. This project ports a proven
battle-tested script (legacy/session-janitor.py, run daily via Task
Scheduler against a production install) into a maintainable package — it
adapts that pipeline; it does not reinvent deletion.
What makes it Devin-native
- Knows the real stores via
devin-internals-spec:sessions.dbrows (schema-version gated), GUIacp-messages/*.dbfiles, andsession_locks/— no guessing at foreign-key graphs or file naming. - Exports transcripts before deleting (
--export-cmdhook, aborts the whole run on failure). - Pluggable judge for ambiguous sessions —
--judge command:<cmd>pipes a JSON payload to any local CLI you trust (e.g. a poordjaevin or Devin ACP helper), but the defaultnoneis purely rules-based and keeps everything ambiguous (fail-open). No external model or service is required. - Retries locked deletions via a pending queue instead of force-killing
Devin;
VACUUMonly runs when Devin is closed.
Install
Requires Python ≥ 3.10 and pipx or uv. Per-OS setup lives in the platform guides: Linux · Personal Windows · Corporate Windows.
Source-only distribution. This tool is not yet published to PyPI. Install from source:
pipx install git+https://github.com/Icaro0310/devin-janitor.git # or uv tool install git+https://github.com/Icaro0310/devin-janitor.git
Usage
devin-janitor scan # classification preview
devin-janitor scan --json # machine-readable
devin-janitor run # dry-run: prints the exact plan, writes nothing
devin-janitor run --apply # execute the pipeline
devin-janitor run --apply --grace-hours 72 \
--export-cmd "devin-history export" # safe recipe: export first
devin-janitor run --judge "command:python my_judge.py" # plug your own judge
devin-janitor pending --list # locked files queued for retry
devin-janitor pending --retry # retry them now
devin-janitor report # recoverable-space report (advisory)
devin-janitor report --json # machine-readable
devin-janitor report --exclude-labeled # drop bridge-labeled sessions from the counts
devin-janitor run --apply --tiers 1,2 # default scope: orphans/cache + stale sessions
devin-janitor run --apply --tiers all --include-gui \
--snapshot /path/to/devin-backup-snapshot # tier3 requires a fresh verified snapshot
devin-janitor install --daily # schedule a daily read-only 'report' job (F6)
Cleanup tiers
Everything the janitor can reclaim falls into three tiers, reported per-tier
by report and selectable via run --tiers:
- tier1 — orphans & cache (default): checkpoint sidecars, message-table
rows whose session is gone, stale
session_locks/*.lock, dead-session leftovers inacp-messages/. No session content is lost. - tier2 — stale sessions (default): sessions past
--grace-hoursthe classifier marksauto_delete(plus judge deletes / pending-queue ids). - tier3 — GUI session state (opt-in):
windsurfSpace.sessionWorkspace/*keys instate.vscdb. Destructive —run --apply --tiers 3refuses unless you pass--include-guiand--snapshot PATHpointing at a verifieddevin-backupsnapshot manifest younger than 24h that coversstate.vscdb, and Devin must be closed.--applyis never scheduled — deletion stays manual.
Automatic sessions (bridge labels)
Sessions created by automation (devin-bridge and friends) carry
origin:purpose labels recorded in <bridge-state>/session-labels.json.
report reads that sidecar (--labels-file to override), lists the
labeled sessions in an automatic sessions section, and marks them
deterministically — --exclude-labeled drops them from the
classification so the report reflects only non-automation sessions.
Scheduled daily report
devin-janitor install --daily registers a read-only daily
devin-janitor report using the F6 scheduling pattern shared across the
devin-* ecosystem: a tagged @daily crontab line
(# devin-ecosystem:devin-janitor-daily), a Task Scheduler entry on
Windows, or an elapsed-time job record in
<config-dir>/.devin-ecosystem/scheduled.json ticked by the
UserPromptSubmit hook when neither scheduler exists. Pin a backend with
--backend auto|tasksch|cron|elapsed. Only report is ever scheduled —
--apply stays a manual decision.
Session data defaults to %APPDATA%\devin on Windows and
$XDG_DATA_HOME/devin (normally ~/.local/share/devin) on Linux. UI ACP files
use $XDG_CONFIG_HOME/Devin (normally ~/.config/Devin). Override with
--data-dir/DEVIN_DATA_DIR and --config-dir/DEVIN_CONFIG_DIR. Protect
sessions in .devin/janitor-keep.json
({"ids": [...], "title_patterns": [...]}); tune classification rules via
--config file.json. report reads every store (sessions.db,
acp-messages/, state.vscdb, session_locks/) and estimates what the
janitor's own rules would free — it never writes and always exits 0. Full
details: docs/SPEC.md.
Works with Devin alone (Devin-only mode)
devin-janitor needs nothing but Devin itself: it reads Devin's own session
stores and writes only a local audit log. No VM, no tunnel, no message queue,
no model server. The default --judge none keeps the whole pipeline
rules-based and fully offline.
Two honest caveats for restricted machines:
runis a dry-run by default; only--applydeletes. Always preview first, and consider--export-cmd "devin-history export"so transcripts are archived before removal.- If you want a semantic judge for ambiguous sessions, plug one in via
--judge command:<cmd>— a small script calling poordjaevin with its Devin ACP backend gives you a Devin-native judge with no extra infrastructure.
Platform support
Tested on Windows and Linux (windows-latest + ubuntu-latest in CI).
Session data uses %APPDATA%/devin on Windows and $XDG_DATA_HOME/devin on
Linux (default ~/.local/share/devin). ACP files use the separate
$XDG_CONFIG_HOME/Devin root on Linux (default ~/.config/Devin). Explicit
--data-dir, --config-dir, --sessions-db, --acp-dir, and --locks-dir
overrides are available.
Limitations
- With the default
--judge none, classification is purely rules-based: ambiguous low-activity sessions are always kept (fail-open), so some noise survives unless you opt into a judge backend. - Devin's stores are private internals; schema versions beyond v17 make the tool stop loudly rather than misparse.
- By default it deletes sessions only —
state.vscdbGUI keys are tier3, gated behind--include-gui+ a verified <24hdevin-backupsnapshot — and it never touches anything without a dry-run preview first.
Development
pip install -e ".[dev]"
python -m pytest
When to use this
- Your session list is drowning in noise — empty sessions, automation/eval probes, one-shot heartbeat cycles, duplicates (~55% of sessions on a real install).
- You want cleanup that archives first:
--export-cmd(e.g.devin-history export) saves transcripts before anything is deleted, and aborts the whole run if the export fails. - You want a reviewable plan, not blind deletion —
runis a dry-run until--apply, with tiered classification you can inspect viascan. - You want locked files handled gracefully — they go to a pending queue for
retry instead of force-killing Devin, and
VACUUMonly runs when Devin is closed.
When NOT to use this
- You expect ambiguous sessions to be auto-judged — the default
--judge nonekeeps everything ambiguous (fail-open); plug in a judge command if you want semantic calls. - You need unattended deletion — only
reportis schedulable (install --daily);--applyalways requires a human in the loop. - You want tier3 GUI-state cleanup without a verified
devin-backupsnapshot — the guard refuses on purpose. - You cannot review a dry-run first — that review is the safety model, and
--applywithout reading the plan defeats it.
FAQ
What is devin-janitor? A lifecycle manager for Devin's session stores. It classifies sessions into tiers (safe noise vs keep vs ambiguous), exports transcripts before deleting, retries locked files through a pending queue, and vacuums only when Devin is closed.
Is it safe? Will it delete real work? run is a dry-run by default —
it prints the exact plan and writes nothing until --apply. Classification
is rules-based and fail-open: ambiguous sessions are kept unless you opt
into a --judge command:<cmd> backend. Protect specific sessions in
.devin/janitor-keep.json and use --export-cmd so nothing is lost.
What happens to locked or in-use files? They are not force-deleted.
Locked deletions go into a pending queue (devin-janitor pending --list,
--retry) and are retried later; VACUUM runs only when Devin is closed.
Does it need an external service or model? No. The default pipeline is
purely rules-based and fully offline — it reads Devin's own stores and
writes a local audit log. A semantic judge for ambiguous sessions is
opt-in via --judge command:<cmd> (for example a poordjaevin ACP script).
License
MIT — see LICENSE.
Metadata
Release files for devin-janitor 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| devin_janitor-0.1.0.tar.gz | 53.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| devin_janitor-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 95.8 kB
Release files / devin_janitor-0.1.0.tar.gz
| Download URL | devin_janitor-0.1.0.tar.gz |
|---|---|
| Size | 53.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
80618d72d12349b9218a4c000ddb1c832e5a9a1d9f9711192970c90e61e64f0b
|
|
BLAKE2b-256 checksum How to use checksums |
8c555c9854f568a0a23615aea5c5b6b20268a5228ff7360763d78f260c9a92eb
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.2
|
Release files / devin_janitor-0.1.0-py3-none-any.whl
| Download URL | devin_janitor-0.1.0-py3-none-any.whl |
|---|---|
| Size | 42.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
7c96a332b7c0a654398c7b8fcb9797de2be2fefa0a202f9b18fc1ebc60bb9f92
|
|
BLAKE2b-256 checksum How to use checksums |
9835cef5f06b52e365518cb4961e145f020b0964c38d96f4bf6d9336a5019bc2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.2
|