# pindoc

**Category:** 🧠 Knowledge & Memory  
**Repository:** https://github.com/var-gg/pindoc  
**Views:** 0  
**Installs:** 0  
**Upvotes:** 0  
**Directory Page:** https://allmcps.com/mcp/pindoc

## Description
Code-pinned team memory for AI coding agents — typed artifacts, MCP-native, self-host.

## Claude Desktop Quick Installation
Heuristic fallback — verify the package name and runner against the repository README before running it. Uses `npx` (confidence: low):

```json
"mcpServers": {
  "pindoc": {
    "command": "npx",
    "args": ["-y","pindoc"]
  }
}
```

## Documentation & README

# Pindoc

<p>
  <a href="https://github.com/var-gg/pindoc/blob/HEAD/README.md"><img alt="English README" src="https://img.shields.io/badge/lang-English-2563eb.svg?style=flat-square"></a>
  <a href="https://github.com/var-gg/pindoc/blob/HEAD/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>
</p>

[![CI](https://github.com/var-gg/pindoc/actions/workflows/ci.yml/badge.svg)](https://github.com/var-gg/pindoc/actions/workflows/ci.yml)
[![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](LICENSE)
[![MCP](https://img.shields.io/badge/MCP-agent%20memory-4b5563.svg)](docs/README.md#agent-workflow-and-mcp)

> **Code-pinned team memory for AI-assisted development.**
> Agents write the durable record; humans review, discuss, and steer.

Pindoc is a self-hosted project memory system for teams working with AI coding
agents. It turns useful agent discoveries into typed artifacts: decisions,
debugging paths, task closeouts, verification notes, and code-linked analyses.
Every artifact is scoped to a project area and pinned back to commits, files,
URLs, resources, or related Pindoc artifacts.

It is still the wiki you never type into, but the point is not automation for
its own sake. Pindoc keeps the parts of agent work that teammates and future
agents can reuse.

## Why It Exists

AI coding sessions are productive, but team context still falls through the
cracks:

- a debugging path dies with the terminal session,
- the same decision is re-explained to every new agent,
- useful analysis stays in one operator's chat instead of becoming team
  knowledge,
- duplicate documents accumulate across wikis, issue trackers, PRs, and commit
  messages,
- in real project environments, the person who finds a problem cannot always
  change the code immediately; structured evidence helps the team discuss and
  decide.

Pindoc turns agent work worth keeping into searchable, code-pinned team memory.
The next teammate or coding agent can ask Pindoc what matters before it edits.

## What Makes Pindoc Different

- **Collaborative memory layer**: artifacts are written for teammates and future agents, not as private chat summaries.
- **Agent-only write surface**: the Reader UI is for reading and review; durable writes go through agents.
- **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.
- **Typed artifacts**: Decision, Analysis, Debug, Flow, Task, TC, Glossary, and domain-pack types.
- **Code-pinned memory**: artifacts can point to commits, files, line ranges, resources, URLs, and related artifacts.
- **Record-worthy by design**: Pindoc avoids raw chat archives and keeps only decisions, analyses, debug paths, verification, and task context with future value.
- **Multi-project daemon**: one `/mcp` endpoint can serve multiple projects; each tool call carries `project_slug`.
- **Self-host first**: Docker Compose brings up Postgres, pgvector, the Pindoc daemon, and the Reader SPA.

## Public Demo

A read-only public demo is a follow-up track and is not part of this OSS
release. Until it ships, the README, [docs/](https://github.com/var-gg/pindoc/blob/HEAD/docs/README.md), and a
self-hosted clone are the primary proof. Operators who want to evaluate
Pindoc end-to-end run `docker compose up -d --build` and inspect their own
artifacts.

The follow-up demo plan stays in [Public Demo Plan](https://github.com/var-gg/pindoc/blob/HEAD/docs/22-public-demo.md)
for when a hosted instance is appropriate.

## Quick Start

Prerequisites:

- Docker 27+
- 2 CPU cores and 4 GB RAM recommended for local dogfood or small-team use
- 5 GB free disk recommended for Docker images, Postgres data, and the
  embedding cache; 2 GB is a light fresh-clone minimum
- outbound HTTPS on first run so the bundled EmbeddingGemma model and runtime
  can be cached
- Go 1.25+ only for host-native development
- Node 20.15+ and pnpm 10+ only for web development outside Docker

The default Docker path includes semantic search through a bundled
EmbeddingGemma Q4 ONNX provider, so no embedding sidecar is required. See
[System Requirements](https://github.com/var-gg/pindoc/blob/HEAD/docs/26-system-requirements.md) for minimum and optional
deployment profiles.

```bash
git clone https://github.com/var-gg/pindoc.git
cd pindoc
docker compose up -d --build
```

To make the running daemon report the exact source revision, pass the current
commit through the Compose build argument before building:

```bash
export PINDOC_BUILD_COMMIT="$(git rev-parse HEAD)"
docker compose up -d --build
```

PowerShell users can set the same value with
`$env:PINDOC_BUILD_COMMIT = git rev-parse HEAD`. `make compose-up` performs
this stamping automatically.

Open the Reader:

```text
http://localhost:5830/
```

Check that the database ledger matches the migrations embedded in the image:

```bash
docker compose exec pindoc-server-daemon pindoc-admin schema doctor --json
```

The command is read-only and exits non-zero for unknown applied migrations,
pending migrations, or checksum drift. It never deletes or accepts an unknown
schema change automatically.

Preview and repair semantic indexes that are unknown, stale, failed, or were
built with a different embedding model:

```bash
docker compose exec pindoc-server-daemon pindoc-reembed -dry-run -state needs-refresh
docker compose exec pindoc-server-daemon pindoc-reembed -state needs-refresh
```

Pindoc records the indexed revision, title/body hashes, model identity,
attempt count, and last error in `artifact_index_state`. Embeddings are fully
prepared before old chunks are replaced. If the provider fails, the artifact
write can still succeed with `index_state.status="failed"` and
`retryable=true`, while the last known-good chunks remain searchable. The
re-embed command handles each artifact in its own transaction and exits
non-zero if any retry still fails.

On a fresh instance, `/` first asks for the owner identity (display name and
email), then routes to the first-project wizard. To open the project wizard
directly after identity setup:

```text
http://localhost:5830/projects/new?welcome=1
```

### Repair Ownerless Projects From Older REST Builds

Older builds could create a project through `POST /api/projects` without a
matching `project_members` owner row. After upgrading, repair any affected
project by assigning the configured loopback owner:

```sql
INSERT INTO project_members (project_id, user_id, role)
SELECT p.id, s.default_loopback_user_id::uuid, 'owner'
FROM projects p
CROSS JOIN server_settings s
WHERE p.slug = '<project-slug>'
  AND s.default_loopback_user_id IS NOT NULL
ON CONFLICT (project_id, user_id) DO UPDATE SET role = 'owner';
```

## Connect an MCP Client

The Docker daemon exposes one account-level MCP endpoint:

```jsonc
{
  "mcpServers": {
    "pindoc": {
      "type": "http",
      "url": "http://127.0.0.1:5830/mcp"
    }
  }
}
```

Project scope is not encoded in the URL. Agents pass `project_slug` on
project-scoped tool calls. Workspaces generated by `pindoc.harness.install`
store that slug in `PINDOC.md` frontmatter. `pindoc.workspace.detect`
resolves the likely slug for the current workspace, but it does not mutate the
daemon-wide `PINDOC_PROJECT` default. In a multi-project Docker daemon, keep
passing the detected `project_slug` explicitly after the session sweep.

`completeness=draft` is a maturity/trust state, not an unpublished private
draft. Accepted MCP writes are still published and Reader-visible when
visibility allows. Use `visibility=private` or the review workflow for content
that must not appear on the normal user surface.

## Common Workflows

Ask an agent to start work with project context:

```text
Use Pindoc context before editing. Find the current project, inspect assigned
Tasks, then implement the next acceptance item.
```

Typical MCP loop:

1. `pindoc.workspace.detect`
2. `pindoc.task.queue`
3. `pindoc.context_for_task`
4. code or doc work
5. `pindoc.artifact.propose`
6. update Task acceptance and closeout state

### Asset uploads from Docker Desktop / Windows

`pindoc.asset.upload(local_path=...)` reads paths from the MCP server
host/container, not from the Windows client. For Docker Desktop, copy the host
file into the `pindoc-server-daemon` container first:

```powershell
pwsh -File tools/push-asset.ps1 A:\path\image.png -ProjectSlug survival-manager
```

The script prints the JSON input for `pindoc.asset.upload`, including the
container-local `/tmp/pindoc-asset-upload/...` path.

For Reader-visible inline images, two steps are intentionally separate:

1. Put `![alt](https://raw.githubusercontent.com/var-gg/pindoc/HEAD/asset.blob_url)` in `body_markdown`; this controls rendering.
2. Call `pindoc.asset.attach` with `role="inline_image"`; this records revision
   metadata and evidence.

## Configuration

The default Docker path is single-user and loopback-only:

| Variable | Default | Purpose |
| --- | --- | --- |
| `PINDOC_DAEMON_PORT` | `5830` | Host port used by Docker Compose. |
| `PINDOC_PROJECT` | `pindoc` | Default project for unscoped reads/config. |
| `PINDOC_PUBLIC_BASE_URL` | `http://127.0.0.1:${PINDOC_DAEMON_PORT}` | Public base URL used in generated links and OAuth metadata. |
| `PINDOC_BIND_ADDR` | `127.0.0.1:5830` | Security intent. Non-loopback values require an IdP or explicit public unauthenticated opt-in. |
| `PINDOC_AUTH_PROVIDERS` | empty | Identity providers enabled for external requests. Current provider: `github`. |
| `PINDOC_ALLOW_PUBLIC_UNAUTHENTICATED` | `false` | Explicit opt-in for external exposure without an IdP. Use only behind a trusted network/reverse proxy. |
| `PINDOC_FORCE_OAUTH_LOCAL` | `false` | Development flag that routes loopback `/mcp` calls through OAuth bearer auth for local QA. |
| `PINDOC_ALLOWED_ORIGINS` | empty | Comma-separated CORS allowlist. Empty means same-origin only; set explicit origins for cross-origin frontends. |
| `PINDOC_DEV_MODE` | `false` | Development-only flag that permits wildcard CORS for local tooling. Do not enable on public instances. |

Do not expose a writable daemon to the public internet without an identity
provider. For a public read-only demo, keep `/mcp` and mutating HTTP routes
blocked at the reverse proxy; see [SECURITY.md](https://github.com/var-gg/pindoc/blob/HEAD/SECURITY.md) and
[docs/22-public-demo.md](https://github.com/var-gg/pindoc/blob/HEAD/docs/22-public-demo.md).
The daemon also sets baseline security headers itself, including `nosniff`,
clickjacking protection, referrer policy, and hardened asset-blob CSP.

For a writable public or cross-device instance, follow
[docs/oauth-setup.md](https://github.com/var-gg/pindoc/blob/HEAD/docs/oauth-setup.md). It covers GitHub OAuth App setup,
the `${PINDOC_PUBLIC_BASE_URL}/auth/github/callback` callback rule, runtime
MCP client registration, and local OAuth QA with `PINDOC_FORCE_OAUTH_LOCAL`.

## Development

```bash
# Run Go tests. Integration tests that need Postgres are skipped unless
# PINDOC_TEST_DATABASE_URL is set.
go test ./...

# Web checks.
cd web
pnpm install --frozen-lockfile
pnpm typecheck
pnpm test:unit
pnpm build

# Full image build.
docker build -t pindoc-server:local .
```

To test the OAuth bearer path locally while still connecting through
`127.0.0.1`, set `PINDOC_FORCE_OAUTH_LOCAL=true`; the daemon will warn on boot
and require Bearer tokens for loopback `/mcp` calls.

On Windows hosts without a local C toolchain, run Go tests through Docker:

```powershell
docker run --rm -v "${PWD}:/work" -w /work golang:1.25 go test ./...
```

Run database integration tests against a disposable Postgres/pgvector database;
never point `PINDOC_TEST_DATABASE_URL` at a personal or production Pindoc
database. Test and plugin fixtures must opt into Reader isolation explicitly:
set `projects.CreateProjectInput.ReaderHidden` to `true`, or set
`projects.reader_hidden = TRUE` when inserting with SQL. Slug-prefix detection is
deprecated and no longer runs at request time. Migration `0070` only performs a
one-time backfill for fixture prefixes used by older Pindoc releases.

## Documentation

- [Documentation Hub](https://github.com/var-gg/pindoc/blob/HEAD/docs/README.md)
- [Public Demo Plan](https://github.com/var-gg/pindoc/blob/HEAD/docs/22-public-demo.md)
- [Public Demo Story Path](https://github.com/var-gg/pindoc/blob/HEAD/docs/25-public-demo-story-path.md)
- [Record-worthy Artifact Policy](https://github.com/var-gg/pindoc/blob/HEAD/docs/24-record-worthy-artifact-policy.md)
- [Public Release Checklist](https://github.com/var-gg/pindoc/blob/HEAD/docs/23-public-release-checklist.md)
- [Contributing](https://github.com/var-gg/pindoc/blob/HEAD/CONTRIBUTING.md)
- [Security](https://github.com/var-gg/pindoc/blob/HEAD/SECURITY.md)
- [Design source notes](https://github.com/var-gg/pindoc/blob/HEAD/docs/README.md#design-source-notes)

## Feedback

Long-form questions, feature requests, and design discussions go to
[GitHub Discussions](https://github.com/var-gg/pindoc/discussions). Bug reports
go to [GitHub Issues](https://github.com/var-gg/pindoc/issues). The maintainer
typically responds within a day.

## Status

Pindoc is in active dogfood. The local self-host path, Reader UI, project/area
model, artifact proposal flow, task queue, revision history, summaries, and
real embedding provider path are implemented. The public OSS launch track is
focused on first-run reliability, a read-only dogfood demo, CI, security docs,
and clearer collaborative positioning.

## License

Apache License 2.0. See [LICENSE](https://github.com/var-gg/pindoc/blob/HEAD/LICENSE).

