# Contributing

> Public mirror PR flow, `bun install` and `bun run check` gate, package layout, changeset requirements, and local dev commands for app and docs site.

- Repository: sashimikun/open-knowledge
- GitHub: https://github.com/sashimikun/open-knowledge
- Human docs: https://grok-wiki.com/public/docs/sashimikun-open-knowledge-5c45105c876e
- Complete Markdown: https://grok-wiki.com/public/docs/sashimikun-open-knowledge-5c45105c876e/llms-full.txt

## Source Files

- `CONTRIBUTING.md`
- `AGENTS.md`
- `package.json`
- `.changeset/config.json`
- `.github/workflows/monorepo-pr-bridge.yml`
- `docs/package.json`
- `.env.example`

---

---
title: "Contributing"
description: "Public mirror PR flow, `bun install` and `bun run check` gate, package layout, changeset requirements, and local dev commands for app and docs site."
---

Open Knowledge is developed in Inkeep's internal monorepo at `inkeep/agents-private` under `public/open-knowledge/` and mirrored to this public repository with Copybara. Public contributions open pull requests here; the `monorepo-pr-bridge` workflow syncs each PR into the internal tree for review and merge, then Copybara syncs accepted changes back. Local validation before requesting review is `bun install` followed by `bun run check`, which runs Biome and Oxlint linting plus Turbo `build`, `typecheck`, and `test` across workspaces.

## Public mirror PR flow

Review and merge decisions happen in the internal mirror so public and internal development stay on the same history. The public PR is closed (not merged) once the change lands via mirror sync.

```mermaid
sequenceDiagram
    participant Contributor
    participant PublicRepo as inkeep/open-knowledge
    participant Bridge as monorepo-pr-bridge
    participant Internal as agents-private/public/open-knowledge
    participant Copybara
    participant Release as release.yml

    Contributor->>PublicRepo: Open PR
    PublicRepo->>Bridge: pull_request_target event
    Bridge->>Internal: Sync branch public-pr/open-knowledge-{N}
    Note over Internal: Maintainer review + merge
    Internal->>Copybara: Accepted change
    Copybara->>PublicRepo: Sync to main (bot commit)
    PublicRepo->>Contributor: Close PR (not merge)
    opt Behavior-changing PR with changeset
        Copybara->>Release: Mirror .changeset/** change
        Release->>Release: Beta publish to npm + DMG
    end
```

<Steps>
<Step title="Fork and branch">

Clone the public repository, create a focused branch, and keep changes scoped to one concern.

</Step>

<Step title="Open a pull request">

Open the PR against `main` on `inkeep/open-knowledge` (or your fork targeting that base). The bridge workflow skips PRs whose head ref is `copybara/sync` — those originate from the internal sync path.

</Step>

<Step title="Wait for mirror automation">

Within about one minute, a bot posts a sticky comment on your PR indicating that an internal mirror PR has been opened. The link points to a private repository and is not accessible to external contributors; that is expected.

</Step>

<Step title="Address feedback and land the change">

Maintainers review in the internal mirror. Once merged internally, Copybara syncs the change to public `main` and your PR is closed automatically. Your authorship is preserved in PR history and the internal commit even though the synced commit on `main` is attributed to the sync bot.

</Step>
</Steps>

### What to expect on your PR

| Signal | Where it runs | What you see |
| --- | --- | --- |
| Mirror notification | Public PR | Sticky bot comment with internal PR link (private) |
| LLM code review | Public PR via `claude-code-review.yml` | Automated review comments from Claude on non-draft PRs |
| Lint, typecheck, tests | Internal mirror after bridge | Results are **not** surfaced back to the public PR |
| Maintainer review | Internal mirror | Reviewer comments are **not** auto-mirrored to your PR |

<Warning>

If you do not hear back within a few business days, comment on your public PR to nudge maintainers. That is the right coordination channel — internal review threads are not mirrored automatically.

</Warning>

### Path mapping and export boundary

The bridge rewrites four root-level overlay files when syncing into the monorepo:

| Public path | Internal overlay path |
| --- | --- |
| `README.md` | `copybara/public-open-knowledge-overlay/README.md` |
| `CONTRIBUTING.md` | `copybara/public-open-knowledge-overlay/CONTRIBUTING.md` |
| `AGENTS.md` | `copybara/public-open-knowledge-overlay/AGENTS.md` |
| `.gitignore` | `copybara/public-open-knowledge-overlay/.gitignore` |

All other in-tree paths map under `public/open-knowledge/` via the `MONOREPO_PATH_PREFIX`. The bridge excludes internal-only paths such as `.codex/`, `.claude/`, `.cursor/`, `specs/`, `reports/`, `projects/`, `stories/`, `strategy/`, and `private/`.

<Info>

Only source code, public docs, and build or development scripts are exported to this mirror. Internal planning notes, reports, specs, and agent workspace files are intentionally absent.

</Info>

### Maintainer iteration and force-push

Maintainers may push fixes directly to your fork branch when you have enabled **Allow edits from maintainers**. Coordinate via the public PR thread before force-pushing your branch if a maintainer has been actively iterating — force-push can discard their commits.

## Development setup

A fresh clone requires no `.env` file. Install dependencies and run the public PR quality gate:

<CodeGroup>

```bash title="Install and verify"
bun install
bun run check
```

```bash title="Pin toolchain (optional)"
fnm install          # reads .node-version (24)
mise install         # reads .node-version
volta install node@24
```

</CodeGroup>

### Toolchain requirements

| Requirement | Source | Version |
| --- | --- | --- |
| Bun | `package.json` `packageManager`, `.bun-version` | `1.3.13+` |
| Node.js | `package.json` `engines`, `.node-version` | `24+` |

<Note>

If you are on a different Node version, `bun install` may warn with `EBADENGINE`. Install usually succeeds, but tests and builds may fail — pin Node 24+ before reporting toolchain issues.

</Note>

## Package layout

The root workspace includes `packages/*` and `docs`. Turbo orchestrates `build`, `typecheck`, and `test` with upstream dependency ordering.

:::files
open-knowledge/
├── packages/
│   ├── app/          @inkeep/open-knowledge-app     Web editor (Vite)
│   ├── cli/          @inkeep/open-knowledge         npm CLI (`ok`, `open-knowledge`)
│   ├── core/         @inkeep/open-knowledge-core    Shared domain logic
│   ├── desktop/      @inkeep/open-knowledge-desktop Electron macOS app
│   ├── plugin/       @inkeep/open-knowledge-plugin  Agent integration helpers
│   └── server/       @inkeep/open-knowledge-server  Hocuspocus collaboration server
├── docs/             @inkeep/open-knowledge-docs    Fumadocs documentation site
├── .changeset/       Version and changelog queue
└── .github/          Bridge, release, and review workflows
:::

| Package | npm name | Role |
| --- | --- | --- |
| `packages/cli` | `@inkeep/open-knowledge` | Published CLI entrypoint (`ok`) |
| `packages/core` | `@inkeep/open-knowledge-core` | Shared schemas, config, domain logic |
| `packages/server` | `@inkeep/open-knowledge-server` | Collaboration server and MCP surface |
| `packages/app` | `@inkeep/open-knowledge-app` | Web editor UI |
| `packages/desktop` | `@inkeep/open-knowledge-desktop` | macOS desktop shell |
| `packages/plugin` | `@inkeep/open-knowledge-plugin` | Agent integration package |
| `docs` | `@inkeep/open-knowledge-docs` | Public docs site (private workspace) |

Top-level overlay docs (`README.md`, `CONTRIBUTING.md`, `AGENTS.md`) are public-safe standalone files maintained for the mirror; keep them free of secrets, internal paths, and private customer context.

## Quality gate commands

`bun run check` is the public PR gate. It expands to root linting plus Turbo `build`, `typecheck`, and `test`.

| Command | What it runs |
| --- | --- |
| `bun run check` | `lint` → Turbo `build` + `typecheck` + `test` |
| `bun run lint` | Biome check + Oxlint (`--max-warnings 0`) |
| `bun run format` | Biome write (unsafe) |
| `bun run typecheck` | Turbo `typecheck` across workspaces |
| `bun run test` | Turbo `test` across workspaces |
| `bun run build` | Turbo `build` across workspaces |
| `bun run notices` | Regenerate `THIRD_PARTY_NOTICES.md` |
| `bun run changeset` | Interactive changeset authoring |

For targeted work, run package-scoped commands from the package directory:

```bash
cd packages/app
bun run test
```

<Tip>

For UI or editor changes, run `bun run check` at the root and also run the affected package tests from `packages/app` before requesting review.

</Tip>

Husky and `lint-staged` format staged `packages/**` and `docs/**` files with Biome on commit when hooks are installed via `bun install` (`prepare` script).

## Local development surfaces

<Tabs>
<Tab title="Web editor">

```bash
bun run --filter @inkeep/open-knowledge-app dev
```

The Vite dev server starts after building `@inkeep/open-knowledge-core` and `@inkeep/open-knowledge-server`. Default Vite port is `5173`; override with optional `VITE_PORT` in `.env` (see `.env.example`).

</Tab>

<Tab title="Docs site">

```bash
cd docs
bun run dev
```

The Fumadocs site serves on port `3010`. `postinstall` runs `fumadocs-mdx`; `prebuild` validates links via `bun validate-link`.

</Tab>

<Tab title="Desktop app">

```bash
cd packages/desktop
bun run dev
```

Runs Electron via `electron-vite dev --watch` with upstream Turbo builds.

</Tab>
</Tabs>

### Optional environment variables

All variables are optional. Copy `.env.example` to `.env` only when you need observability or a custom dev port:

<ParamField body="OTEL_SDK_DISABLED" type="boolean">
Set to `false` to enable server-side OpenTelemetry instrumentation.
</ParamField>

<ParamField body="VITE_OTEL_ENABLED" type="boolean">
Set to `true` to enable frontend (Vite) OpenTelemetry instrumentation.
</ParamField>

<ParamField body="OTEL_EXPORTER_OTLP_ENDPOINT" type="string">
OTLP endpoint for traces and metrics. Default: `http://localhost:4318`.
</ParamField>

<ParamField body="VITE_PORT" type="number">
Custom port for the Vite dev server (`packages/app`). Does not affect `ok start` / `ok ui` port resolution.
</ParamField>

## Changesets

Every behavior-changing pull request ships a `.changeset/<descriptive-kebab-slug>.md` file. The body becomes the user-facing entry on the next beta GitHub Release and aggregated stable release notes — how npm consumers and DMG auto-update users learn what changed.

<Check>

Skip changesets for docs-only, test-only, or CI-only edits that do not change runtime behavior.

</Check>

### Authoring

```bash
bun run changeset
```

The interactive CLI writes well-formed frontmatter. You can also hand-write a file, but prefer the CLI.

<RequestExample>

```md title=".changeset/fix-search-ranking.md"
---
"@inkeep/open-knowledge": patch
---

Fix: `ok search` now ranks exact title matches above partial body matches when semantic search is disabled.
```

</RequestExample>

### Pre-1.0 semver convention

While Open Knowledge is below `1.0.0`, bump types follow a **shift-down** convention. **Never declare `major` in a changeset** — a single `major` on any fixed-group package would pull the entire group to `1.0.0`.

| Consumer impact | Pre-1.0 bump type |
| --- | --- |
| Breaking change (rename, removal, schema change) | `minor` |
| New feature or additive API surface | `minor` |
| Bug fix or internal change with no user-visible API impact | `patch` |

### Fixed-group lock-step

These packages bump together on the highest declared bump type across queued changesets:

- `@inkeep/open-knowledge`
- `@inkeep/open-knowledge-core`
- `@inkeep/open-knowledge-server`
- `@inkeep/open-knowledge-app`
- `@inkeep/open-knowledge-desktop`

Do not write inline sibling-package version numbers in changeset bodies — lock-step versions are computed at release time.

### Release cadence

Merging an internal PR that includes a changeset triggers Copybara to mirror `.changeset/**` changes. The `release.yml` workflow on the public mirror then publishes a beta to npm (`@inkeep/open-knowledge@X.Y.Z-beta.N` with `--tag beta`) and dispatches desktop DMG builds within minutes.

Changeset body style:

- Lead with a user-visible verb
- Name the affected command or surface in a code span
- Show before/after when relevant
- Skip internal spec IDs or story numbers

## Contribution guidelines

- Keep pull requests focused and small enough to review.
- Include tests or a clear manual verification note for behavior changes.
- Run `bun run check` before requesting review.
- Commit `bun.lock` when dependency changes require it.
- Run `bun run notices` and include `THIRD_PARTY_NOTICES.md` changes when dependencies affect third-party notices.
- Do not include secrets, credentials, customer data, local machine paths, or generated debug artifacts.
- Keep overlay docs (`README.md`, `CONTRIBUTING.md`, `AGENTS.md`) public-safe and standalone.

## License

Open Knowledge is licensed under the [GNU General Public License v3.0 or later](https://github.com/inkeep/open-knowledge/blob/main/LICENSE) (`GPL-3.0-or-later`). By submitting a contribution, you agree it is licensed under the same terms.

## Related pages

<CardGroup>
<Card title="Installation" href="/installation">
Toolchain prerequisites for contributors: Node.js 24+, Bun 1.3.13+, and install paths for the npm CLI and macOS desktop app.
</Card>
<Card title="Overview" href="/overview">
Monorepo packages, runtime surfaces (desktop app, `ok` CLI web editor, MCP server), and the shortest path from install to first agent-driven edit.
</Card>
<Card title="Troubleshooting" href="/troubleshooting">
Diagnose server lock state, run health diagnostics, repair stale skills/MCP configs, and recover from crash leftovers.
</Card>
</CardGroup>
