project-mgr
v0.2.1
Published
Local-first append-only project status ledger
Readme
Project Manager
project-mgr is a local-first, append-only ledger for project status. It stores progress, blockers, decisions, and next steps as timestamped status snapshots, so people and AI agents can quickly inspect each project's current state, complete history, or state at a particular time.
The first release provides a local CLI, SQLite, and an optional Agent Skill. It has no HTTP API or long-running service. Data stays on the local machine and requires no account or cloud service.
Run from npm
Requires Node.js 22+.
Run without installing:
npx --yes --package project-mgr pmgr currentOr install the CLI globally:
npm install --global project-mgr
pmgr currentThe database defaults to ~/.local/share/project-mgr/project-mgr.sqlite, regardless of the directory where pmgr is executed. The CLI resolves this to an absolute path using the current user's home directory and creates the parent directory automatically.
Set PMGR_DB_PATH to use another location:
PMGR_DB_PATH=/absolute/path/projects.sqlite npx --yes --package project-mgr pmgr currentInstall the Agent Skill
The repository includes the project-mgr skill, shown as project-mgr in skill pickers. It guides compatible AI agents to add, import, query, and export local project status history. Install it with the skills CLI:
npx skills add deanplus/project-managerThe installer detects supported agents and asks where to install the skill. No separate project-mgr installation is required: the skill runs the CLI through npx. Restart or reload the selected agent after installation.
Invoke the skill
In Codex, write $project-mgr in the prompt. Alternatively, type /pro and select project-mgr from the picker. In other agents, use their explicit skill syntax or select project-mgr from the skills menu.
Use normal language after the skill name; the agent translates the request into CLI commands. For example:
Use $project-mgr to show the current status and latest 10 updates for project-mgr.
Use $project-mgr to record this update for project-mgr: active; released the Agent Skill;
next, collect user feedback.
Use $project-mgr to record these updates: api is blocked by authentication; web is active
and the dashboard is complete.
Use $project-mgr with PMGR_DB_PATH=/tmp/project-mgr-test.sqlite to add a test update,
then show its history.The agent should query before writing and ask for missing required values such as the project name, status, or summary.
The skill uses the same PMGR_DB_PATH behavior as the CLI: it defaults to ~/.local/share/project-mgr/project-mgr.sqlite; set an absolute path to work in another ledger. For manual or exploratory work, use a dedicated database such as PMGR_DB_PATH=/tmp/project-mgr-skill-test.sqlite rather than the default ledger.
Build from source
Requires Node.js 22+ and pnpm 10.30.2.
pnpm install --frozen-lockfile
cp .env_sample .env
pnpm build.env_sample provides examples for all environment settings. The copied .env file is ignored by Git. pnpm start and pnpm pmgr automatically load the root .env; existing shell environment variables take precedence.
After building, run:
pnpm start currentDuring development, run the TypeScript CLI directly:
pnpm pmgr currentThe default database path is:
~/.local/share/project-mgr/project-mgr.sqlitePMGR_DB_PATH is optional in .env_sample. Set it in .env to use another location, or override it for one command:
PMGR_DB_PATH=/absolute/path/projects.sqlite pnpm start currentUse a literal absolute path in .env; .env files do not expand ~ or $HOME. The database is created automatically when the first valid command runs.
Use an isolated test database
For manual testing, set a persistent path in .env that is separate from production data:
PMGR_DB_PATH=/tmp/project-mgr-manual-test.sqliteThen run commands normally:
pnpm start add \
--project test-project \
--status active \
--summary "Testing the isolated database"
pnpm start history --project test-projectProject keys must match exactly: a record added to test-project is not part of project-mgr history. Empty human-readable list queries print No entries found.; with --json, they print [].
Delete /tmp/project-mgr-manual-test.sqlite when it is no longer needed.
Automated tests use an in-memory database or SQLite files in the system temporary directory; they do not read or write the default database. PMGR_DB_PATH=:memory: also works for one command, but each CLI command runs in a separate process and its data disappears when the command exits, so it is not suitable for consecutive manual tests.
Quick start
Append a project status:
pnpm start add \
--project project-mgr \
--status active \
--summary "The local status ledger is available" \
--progress "Completed SQLite and CLI support" \
--next "Connect a real project" \
--tag mvpQuery the current status of all projects or one project:
pnpm start current
pnpm start current --project project-mgr --jsonQuery history and the status at a specified time:
pnpm start history \
--project project-mgr \
--since 2026-08-01T00:00:00Z \
--limit 20 \
--offset 0
# Recent history across every project.
pnpm start history --limit 20 --json
pnpm start at \
--project project-mgr \
--at 2026-08-03T12:00:00+08:00 \
--jsonWrite status
add requires:
--project: Unique project name. It may contain English letters, numbers,.,_, and-, and must start with a letter or number.--summary: A summary of this status.
Optional arguments:
--status: One ofidea,planned,active,blocked,paused,completed, orarchived(doneis accepted as an alias forcompleted). Defaults tocompletedif omitted.--description: Project introduction or description (updates project metadata).--notes: Persistent, medium-to-long-term project notes/remarks (e.g., architectural constraints, key caveats; updates project metadata).--progress: Work already completed.--blocker,--next,--decision, and--tag: May be specified repeatedly.--at: When the status actually occurred. It must be an ISO 8601 timestamp with a timezone; defaults to the current time.--source:human,agent, orimport; defaults tohuman.--external-ref: A globally idempotent key. A duplicate write to the same project returns the existing record; use by another project is an error.--json: Emit stable JSON.
Project Metadata & Fuzzy Search
Set or update a project's display name, description, and notes with set-project, or clear metadata using --clear-description / --clear-notes:
pnpm start set-project \
--project project-mgr \
--display-name "Project Manager" \
--description "Local-first append-only project status ledger" \
--notes "Core CLI and Agent Skill are published"
# Clear description or notes
pnpm start set-project --project project-mgr --clear-description --clear-notesList projects or search projects using fuzzy matching across slug, display name, description, notes, latest status summary, and tags with projects (or list):
pnpm start projects
pnpm start list --query "ledger"
pnpm start projects --query "mvp" --jsonBulk import
import accepts a JSON object, a JSON array, or a JSONL file containing one object per line. Every record is validated before the whole batch is written in one SQLite transaction; any failure rolls back the entire batch.
{
"project": "project-mgr",
"status": "active",
"summary": "Core functionality is complete",
"progress": "CLI and SQLite have passed tests",
"blockers": [],
"nextSteps": ["Connect a real project"],
"decisions": ["The first release provides only a local CLI"],
"tags": ["mvp"],
"occurredAt": "2026-08-03T12:00:00+08:00",
"source": "human",
"externalRef": "project-mgr-2026-08-03-core"
}pnpm start import statuses.jsonl
# Equivalent form
pnpm start import --file statuses.jsonl --jsonUnknown fields, unknown CLI options, extra positional arguments, invalid statuses, and timestamps without a timezone are rejected.
Local Web Dashboard
Launch a local HTTP server to view project overviews and project activity history in your browser:
pmgr serveBy default, pmgr serve listens on http://127.0.0.1:3000 and automatically opens the web dashboard in your default browser.
Options:
--port: HTTP server port (default:3000orPORTenvironment variable).--host: Host interface to bind (default:127.0.0.1).--no-open: Do not automatically open the web browser.--json: Output server startup details in JSON format.
REST API Endpoints
The server also exposes JSON API endpoints:
GET /api/projects: List project overviews (supports?query=...).GET /api/projects/:slug: Detailed metadata and latest status of a specific project.GET /api/history: Timeline activity log across all or specific projects (supports?project=...,?since=...,?until=...,?limit=...,?offset=...).GET /api/stats: Overview metrics (total projects count, status breakdowns, total activity entries count).
Query and export
| Command | Purpose | Key options |
| ------------- | ----------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
| projects | List all projects or fuzzy search by query | --query, --json |
| set-project | Set/update project display name, description, & notes | --project, --display-name, --description, --notes, --clear-description, --clear-notes, --json |
| current | Current status for all projects or one project | --project, --json |
| history | History for all projects or one project, newest first | --project, --since, --until, --limit, --offset, --json |
| at | The latest status at or before a specified time | --project, --at, --json |
| export | Export all records or one project's records | --project, --format json\|jsonl |
| serve | Start local HTTP server & interactive web dashboard | --port, --host, --open, --no-open, --json |
All actions can also use the compatible status <action> form, for example pmgr status projects. Human-readable multi-record results list projects and their latest status, or No entries found. / No projects found. when empty. add, import, current, projects, list, set-project, history, at, and serve support --json; export uses --format to select its format.
Exports omit the database-internal id and recordedAt fields and can be imported directly. Records are exported from oldest to newest so that restoring them preserves the insertion order of records with the same timestamp:
pnpm start export --format jsonl > project-statuses.jsonl
PMGR_DB_PATH=/tmp/project-mgr-restored.sqlite \
pnpm start import project-statuses.jsonlDevelopment and verification
pnpm typecheck
pnpm lint
pnpm format-check
pnpm test
pnpm coverage
pnpm buildCoverage thresholds for statements, branches, functions, and lines are all 100%. See the architecture document for the detailed design.
