{
  "markdown": "# Pindoc\n\n<p>\n  <a href=\"./README.md\"><img alt=\"English README\" src=\"https://img.shields.io/badge/lang-English-2563eb.svg?style=flat-square\"></a>\n  <a href=\"./README-ko.md\"><img alt=\"Korean README\" src=\"https://img.shields.io/badge/lang-%ED%95%9C%EA%B5%AD%EC%96%B4-6b7280.svg?style=flat-square\"></a>\n</p>\n\n[![CI](https://github.com/var-gg/pindoc/actions/workflows/ci.yml/badge.svg)](https://github.com/var-gg/pindoc/actions/workflows/ci.yml)\n[![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](LICENSE)\n[![MCP](https://img.shields.io/badge/MCP-agent%20memory-4b5563.svg)](docs/README.md#agent-workflow-and-mcp)\n\n> **Code-pinned team memory for AI-assisted development.**\n> Agents write the durable record; humans review, discuss, and steer.\n\nPindoc is a self-hosted project memory system for teams working with AI coding\nagents. It turns useful agent discoveries into typed artifacts: decisions,\ndebugging paths, task closeouts, verification notes, and code-linked analyses.\nEvery artifact is scoped to a project area and pinned back to commits, files,\nURLs, resources, or related Pindoc artifacts.\n\nIt is still the wiki you never type into, but the point is not automation for\nits own sake. Pindoc keeps the parts of agent work that teammates and future\nagents can reuse.\n\n## Why It Exists\n\nAI coding sessions are productive, but team context still falls through the\ncracks:\n\n- a debugging path dies with the terminal session,\n- the same decision is re-explained to every new agent,\n- useful analysis stays in one operator's chat instead of becoming team\n  knowledge,\n- duplicate documents accumulate across wikis, issue trackers, PRs, and commit\n  messages,\n- in real project environments, the person who finds a problem cannot always\n  change the code immediately; structured evidence helps the team discuss and\n  decide.\n\nPindoc turns agent work worth keeping into searchable, code-pinned team memory.\nThe next teammate or coding agent can ask Pindoc what matters before it edits.\n\n## What Makes Pindoc Different\n\n- **Collaborative memory layer**: artifacts are written for teammates and future agents, not as private chat summaries.\n- **Agent-only write surface**: the Reader UI is for reading and review; durable writes go through agents.\n- **MCP-native workflow**: tools such as `pindoc.context_for_task`, `pindoc.artifact.propose`, and `pindoc.task.queue` regulate agent behavior instead of acting as a thin CRUD API.\n- **Typed artifacts**: Decision, Analysis, Debug, Flow, Task, TC, Glossary, and domain-pack types.\n- **Code-pinned memory**: artifacts can point to commits, files, line ranges, resources, URLs, and related artifacts.\n- **Record-worthy by design**: Pindoc avoids raw chat archives and keeps only decisions, analyses, debug paths, verification, and task context with future value.\n- **Multi-project daemon**: one `/mcp` endpoint can serve multiple projects; each tool call carries `project_slug`.\n- **Self-host first**: Docker Compose brings up Postgres, pgvector, the Pindoc daemon, and the Reader SPA.\n\n## Public Demo\n\nA read-only public demo is a follow-up track and is not part of this OSS\nrelease. Until it ships, the README, [docs/](docs/README.md), and a\nself-hosted clone are the primary proof. Operators who want to evaluate\nPindoc end-to-end run `docker compose up -d --build` and inspect their own\nartifacts.\n\nThe follow-up demo plan stays in [Public Demo Plan](docs/22-public-demo.md)\nfor when a hosted instance is appropriate.\n\n## Quick Start\n\nPrerequisites:\n\n- Docker 27+\n- 2 CPU cores and 4 GB RAM recommended for local dogfood or small-team use\n- 5 GB free disk recommended for Docker images, Postgres data, and the\n  embedding cache; 2 GB is a light fresh-clone minimum\n- outbound HTTPS on first run so the bundled EmbeddingGemma model and runtime\n  can be cached\n- Go 1.25+ only for host-native development\n- Node 20.15+ and pnpm 10+ only for web development outside Docker\n\nThe default Docker path includes semantic search through a bundled\nEmbeddingGemma Q4 ONNX provider, so no embedding sidecar is required. See\n[System Requirements](docs/26-system-requirements.md) for minimum and optional\ndeployment profiles.\n\n```bash\ngit clone https://github.com/var-gg/pindoc.git\ncd pindoc\ndocker compose up -d --build\n```\n\nTo make the running daemon report the exact source revision, pass the current\ncommit through the Compose build argument before building:\n\n```bash\nexport PINDOC_BUILD_COMMIT=\"$(git rev-parse HEAD)\"\ndocker compose up -d --build\n```\n\nPowerShell users can set the same value with\n`$env:PINDOC_BUILD_COMMIT = git rev-parse HEAD`. `make compose-up` performs\nthis stamping automatically.\n\nOpen the Reader:\n\n```text\nhttp://localhost:5830/\n```\n\nCheck that the database ledger matches the migrations embedded in the image:\n\n```bash\ndocker compose exec pindoc-server-daemon pindoc-admin schema doctor --json\n```\n\nThe command is read-only and exits non-zero for unknown applied migrations,\npending migrations, or checksum drift. It never deletes or accepts an unknown\nschema change automatically.\n\nPreview and repair semantic indexes that are unknown, stale, failed, or were\nbuilt with a different embedding model:\n\n```bash\ndocker compose exec pindoc-server-daemon pindoc-reembed -dry-run -state needs-refresh\ndocker compose exec pindoc-server-daemon pindoc-reembed -state needs-refresh\n```\n\nPindoc records the indexed revision, title/body hashes, model identity,\nattempt count, and last error in `artifact_index_state`. Embeddings are fully\nprepared before old chunks are replaced. If the provider fails, the artifact\nwrite can still succeed with `index_state.status=\"failed\"` and\n`retryable=true`, while the last known-good chunks remain searchable. The\nre-embed command handles each artifact in its own transaction and exits\nnon-zero if any retry still fails.\n\nOn a fresh instance, `/` first asks for the owner identity (display name and\nemail), then routes to the first-project wizard. To open the project wizard\ndirectly after identity setup:\n\n```text\nhttp://localhost:5830/projects/new?welcome=1\n```\n\n### Repair Ownerless Projects From Older REST Builds\n\nOlder builds could create a project through `POST /api/projects` without a\nmatching `project_members` owner row. After upgrading, repair any affected\nproject by assigning the configured loopback owner:\n\n```sql\nINSERT INTO project_members (project_id, user_id, role)\nSELECT p.id, s.default_loopback_user_id::uuid, 'owner'\nFROM projects p\nCROSS JOIN server_settings s\nWHERE p.slug = '<project-slug>'\n  AND s.default_loopback_user_id IS NOT NULL\nON CONFLICT (project_id, user_id) DO UPDATE SET role = 'owner';\n```\n\n## Connect an MCP Client\n\nThe Docker daemon exposes one account-level MCP endpoint:\n\n```jsonc\n{\n  \"mcpServers\": {\n    \"pindoc\": {\n      \"type\": \"http\",\n      \"url\": \"http://127.0.0.1:5830/mcp\"\n    }\n  }\n}\n```\n\nProject scope is not encoded in the URL. Agents pass `project_slug` on\nproject-scoped tool calls. Workspaces generated by `pindoc.harness.install`\nstore that slug in `PINDOC.md` frontmatter. `pindoc.workspace.detect`\nresolves the likely slug for the current workspace, but it does not mutate the\ndaemon-wide `PINDOC_PROJECT` default. In a multi-project Docker daemon, keep\npassing the detected `project_slug` explicitly after the session sweep.\n\n`completeness=draft` is a maturity/trust state, not an unpublished private\ndraft. Accepted MCP writes are still published and Reader-visible when\nvisibility allows. Use `visibility=private` or the review workflow for content\nthat must not appear on the normal user surface.\n\n## Common Workflows\n\nAsk an agent to start work with project context:\n\n```text\nUse Pindoc context before editing. Find the current project, inspect assigned\nTasks, then implement the next acceptance item.\n```\n\nTypical MCP loop:\n\n1. `pindoc.workspace.detect`\n2. `pindoc.task.queue`\n3. `pindoc.context_for_task`\n4. code or doc work\n5. `pindoc.artifact.propose`\n6. update Task acceptance and closeout state\n\n### Asset uploads from Docker Desktop / Windows\n\n`pindoc.asset.upload(local_path=...)` reads paths from the MCP server\nhost/container, not from the Windows client. For Docker Desktop, copy the host\nfile into the `pindoc-server-daemon` container first:\n\n```powershell\npwsh -File tools/push-asset.ps1 A:\\path\\image.png -ProjectSlug survival-manager\n```\n\nThe script prints the JSON input for `pindoc.asset.upload`, including the\ncontainer-local `/tmp/pindoc-asset-upload/...` path.\n\nFor Reader-visible inline images, two steps are intentionally separate:\n\n1. Put `![alt](<asset.blob_url>)` in `body_markdown`; this controls rendering.\n2. Call `pindoc.asset.attach` with `role=\"inline_image\"`; this records revision\n   metadata and evidence.\n\n## Configuration\n\nThe default Docker path is single-user and loopback-only:\n\n| Variable | Default | Purpose |\n| --- | --- | --- |\n| `PINDOC_DAEMON_PORT` | `5830` | Host port used by Docker Compose. |\n| `PINDOC_PROJECT` | `pindoc` | Default project for unscoped reads/config. |\n| `PINDOC_PUBLIC_BASE_URL` | `http://127.0.0.1:${PINDOC_DAEMON_PORT}` | Public base URL used in generated links and OAuth metadata. |\n| `PINDOC_BIND_ADDR` | `127.0.0.1:5830` | Security intent. Non-loopback values require an IdP or explicit public unauthenticated opt-in. |\n| `PINDOC_AUTH_PROVIDERS` | empty | Identity providers enabled for external requests. Current provider: `github`. |\n| `PINDOC_ALLOW_PUBLIC_UNAUTHENTICATED` | `false` | Explicit opt-in for external exposure without an IdP. Use only behind a trusted network/reverse proxy. |\n| `PINDOC_FORCE_OAUTH_LOCAL` | `false` | Development flag that routes loopback `/mcp` calls through OAuth bearer auth for local QA. |\n| `PINDOC_ALLOWED_ORIGINS` | empty | Comma-separated CORS allowlist. Empty means same-origin only; set explicit origins for cross-origin frontends. |\n| `PINDOC_DEV_MODE` | `false` | Development-only flag that permits wildcard CORS for local tooling. Do not enable on public instances. |\n\nDo not expose a writable daemon to the public internet without an identity\nprovider. For a public read-only demo, keep `/mcp` and mutating HTTP routes\nblocked at the reverse proxy; see [SECURITY.md](SECURITY.md) and\n[docs/22-public-demo.md](docs/22-public-demo.md).\nThe daemon also sets baseline security headers itself, including `nosniff`,\nclickjacking protection, referrer policy, and hardened asset-blob CSP.\n\nFor a writable public or cross-device instance, follow\n[docs/oauth-setup.md](docs/oauth-setup.md). It covers GitHub OAuth App setup,\nthe `${PINDOC_PUBLIC_BASE_URL}/auth/github/callback` callback rule, runtime\nMCP client registration, and local OAuth QA with `PINDOC_FORCE_OAUTH_LOCAL`.\n\n## Development\n\n```bash\n# Run Go tests. Integration tests that need Postgres are skipped unless\n# PINDOC_TEST_DATABASE_URL is set.\ngo test ./...\n\n# Web checks.\ncd web\npnpm install --frozen-lockfile\npnpm typecheck\npnpm test:unit\npnpm build\n\n# Full image build.\ndocker build -t pindoc-server:local .\n```\n\nTo test the OAuth bearer path locally while still connecting through\n`127.0.0.1`, set `PINDOC_FORCE_OAUTH_LOCAL=true`; the daemon will warn on boot\nand require Bearer tokens for loopback `/mcp` calls.\n\nOn Windows hosts without a local C toolchain, run Go tests through Docker:\n\n```powershell\ndocker run --rm -v \"${PWD}:/work\" -w /work golang:1.25 go test ./...\n```\n\nRun database integration tests against a disposable Postgres/pgvector database;\nnever point `PINDOC_TEST_DATABASE_URL` at a personal or production Pindoc\ndatabase. Test and plugin fixtures must opt into Reader isolation explicitly:\nset `projects.CreateProjectInput.ReaderHidden` to `true`, or set\n`projects.reader_hidden = TRUE` when inserting with SQL. Slug-prefix detection is\ndeprecated and no longer runs at request time. Migration `0070` only performs a\none-time backfill for fixture prefixes used by older Pindoc releases.\n\n## Documentation\n\n- [Documentation Hub](docs/README.md)\n- [Public Demo Plan](docs/22-public-demo.md)\n- [Public Demo Story Path](docs/25-public-demo-story-path.md)\n- [Record-worthy Artifact Policy](docs/24-record-worthy-artifact-policy.md)\n- [Public Release Checklist](docs/23-public-release-checklist.md)\n- [Contributing](CONTRIBUTING.md)\n- [Security](SECURITY.md)\n- [Design source notes](docs/README.md#design-source-notes)\n\n## Feedback\n\nLong-form questions, feature requests, and design discussions go to\n[GitHub Discussions](https://github.com/var-gg/pindoc/discussions). Bug reports\ngo to [GitHub Issues](https://github.com/var-gg/pindoc/issues). The maintainer\ntypically responds within a day.\n\n## Status\n\nPindoc is in active dogfood. The local self-host path, Reader UI, project/area\nmodel, artifact proposal flow, task queue, revision history, summaries, and\nreal embedding provider path are implemented. The public OSS launch track is\nfocused on first-run reliability, a read-only dogfood demo, CI, security docs,\nand clearer collaborative positioning.\n\n## License\n\nApache License 2.0. See [LICENSE](LICENSE).\n",
  "bytes": 12977,
  "sha": "7464a3e626053eccec1945b7dcae9610f31ed76036f909d5a37a956e5efb5852",
  "repo_slug": "var-gg/pindoc",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_var_gg_pindoc_6d2fee12/readme"
}