Skip to content

Commit 5d7ea89

Browse files
committed
feat: initial release of opendoc
0 parents  commit 5d7ea89

108 files changed

Lines changed: 18379 additions & 0 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.claude-plugin/marketplace.json

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"name": "arcships",
3+
"owner": {
4+
"name": "arcships"
5+
},
6+
"metadata": {
7+
"description": "arcships' Claude Code plugins."
8+
},
9+
"plugins": [
10+
{
11+
"name": "opendoc",
12+
"source": "./skill",
13+
"description": "Local knowledge base: one-way mirror of authorized Notion/Feishu docs into a local read-only Markdown tree the agent searches directly with Grep/Glob/Read. The binary is not committed — on first use the skill offers a one-time, checksum-verified download of the build for this platform.",
14+
"author": {
15+
"name": "arcships"
16+
}
17+
}
18+
]
19+
}

.github/workflows/ci.yml

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
8+
# Read-only token: CI builds and tests, it never writes to the repo.
9+
permissions:
10+
contents: read
11+
12+
# A newer push to the same branch/PR cancels the in-flight run.
13+
concurrency:
14+
group: ci-${{ github.ref }}
15+
cancel-in-progress: true
16+
17+
jobs:
18+
build-test:
19+
runs-on: ubuntu-latest
20+
steps:
21+
- uses: actions/checkout@v4
22+
23+
- uses: actions/setup-go@v5
24+
with:
25+
# Single source of truth for the Go version: go.mod's `go` directive.
26+
go-version-file: go.mod
27+
cache: true
28+
29+
- name: gofmt
30+
run: |
31+
unformatted="$(gofmt -l . | grep -v '^skill/bin/' || true)"
32+
if [ -n "$unformatted" ]; then
33+
echo "These files are not gofmt-ed:"
34+
echo "$unformatted"
35+
exit 1
36+
fi
37+
38+
- name: go vet
39+
run: go vet ./...
40+
41+
- name: staticcheck
42+
uses: dominikh/staticcheck-action@v1
43+
with:
44+
version: latest
45+
install-go: false
46+
47+
- name: build
48+
run: go build ./...
49+
50+
- name: test (race + coverage)
51+
run: go test -race -covermode=atomic ./...
52+
53+
# The delivery unit is a static, CGO-free single binary.
54+
# Guard that the packaging build still works, not just `go build ./...`.
55+
- name: delivery build (static skill binary)
56+
run: CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o skill/bin/opendoc ./cmd/opendoc

.github/workflows/release.yml

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
name: release
2+
3+
# Tag-triggered. Pushing a tag like v0.1.0 cross-compiles the engine for
4+
# every supported platform, generates sha256 checksums, and publishes them
5+
# as a GitHub Release. The download script (skill/scripts/download-binary.sh)
6+
# consumes these assets. Keep the tag in sync with skill/.claude-plugin/plugin.json.
7+
on:
8+
push:
9+
tags: ['v*']
10+
11+
# gh release create needs write access to create the release and upload assets.
12+
permissions:
13+
contents: write
14+
15+
jobs:
16+
release:
17+
runs-on: ubuntu-latest
18+
steps:
19+
- uses: actions/checkout@v4
20+
21+
- uses: actions/setup-go@v5
22+
with:
23+
go-version-file: go.mod
24+
25+
# Cross-compile all targets in one job — pure-Go, CGO-free, so a single
26+
# Linux runner produces every platform binary in seconds. Flags match
27+
# scripts/build-skill.sh (CGO_ENABLED=0, -trimpath) for reproducibility.
28+
- name: cross-compile
29+
run: |
30+
mkdir -p dist
31+
for target in darwin/arm64 darwin/amd64 linux/amd64 linux/arm64; do
32+
os="${target%/*}"; arch="${target#*/}"
33+
out="dist/opendoc-${os}-${arch}"
34+
echo "building $out"
35+
CGO_ENABLED=0 GOOS="$os" GOARCH="$arch" go build -trimpath -ldflags="-s -w" -o "$out" ./cmd/opendoc
36+
done
37+
( cd dist && sha256sum opendoc-* > checksums.txt && cat checksums.txt )
38+
39+
- name: publish release
40+
env:
41+
GH_TOKEN: ${{ github.token }}
42+
run: |
43+
gh release create "$GITHUB_REF_NAME" \
44+
--repo "$GITHUB_REPOSITORY" \
45+
--title "$GITHUB_REF_NAME" \
46+
--generate-notes \
47+
dist/opendoc-* dist/checksums.txt

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.DS_Store
2+
3+
# built skill binary (produced by scripts/build-skill.sh)
4+
skill/bin/opendoc

AGENTS.md

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# AGENTS.md
2+
3+
## What opendoc is
4+
5+
opendoc is a one-way sync engine that mirrors documents you've authorized in
6+
Notion and Feishu into a local, read-only Markdown tree. It never writes
7+
back to the source platform. The mirror is meant to be consumed directly by
8+
coding agents with Grep/Glob/Read — no API calls, no credentials, no network
9+
access needed at read time. A companion Claude Code plugin (`skill/`) wraps
10+
the `opendoc` binary and exposes it to agents as a skill.
11+
12+
## Repo layout
13+
14+
- `cmd/opendoc` — CLI entrypoint (`main.go`), wires subcommands to `internal/cli`.
15+
- `internal/adapter` — platform-agnostic contract between the engine and a
16+
concrete source (Notion, Feishu, ...); the engine only depends on this interface.
17+
- `internal/cli` — subcommand dispatch and flag parsing (init, sync, status,
18+
doctor, resolve, schedule).
19+
- `internal/config` — on-disk mirror configuration (`.internal/config.toml`)
20+
and its readers/writers.
21+
- `internal/engine` — the sync pipeline: fetch, diff, write, index, manifest bookkeeping.
22+
- `internal/feishu` — Feishu/Lark adapter (bitable, doc fetch, metadata).
23+
- `internal/frontmatter` — deterministic YAML frontmatter rendering for mirrored files.
24+
- `internal/layout` — mirror-root resolution and on-disk directory layout.
25+
- `internal/manifest``manifest.sqlite`, the sync engine's bookkeeping ledger.
26+
- `internal/naming` — filesystem-safe path/file naming and collision rules.
27+
- `internal/notion` — Notion adapter (query, fetch, properties→frontmatter mapping).
28+
- `internal/ratelimit` — token bucket + backoff helpers for platform QPS limits.
29+
30+
## Build & test
31+
32+
```
33+
go build ./...
34+
go test ./...
35+
./scripts/build-skill.sh # builds the binary into skill/bin/opendoc and symlinks it into ~/.claude/skills/opendoc
36+
```
37+
38+
## Key invariants
39+
40+
- **Fidelity-first**: never silently drop content. Anything that can't be
41+
rendered faithfully gets a placeholder tag, and the loss is counted in the
42+
sync report — not swallowed.
43+
- **Mirror is read-only**: nothing in the mirrored tree is ever written back
44+
to Notion or Feishu.
45+
- **Manifest keys are platform-native IDs**: the sync ledger is keyed by the
46+
source platform's own document/page/row IDs, not derived or local ones.
47+
- **content_hash is computed before link rewriting**: the hash that drives
48+
change detection reflects the fetched content, not the post-processed
49+
(link-rewritten) output.
50+
- **Doctor codes are stable identifiers**: probe/failure codes (e.g. `F1`,
51+
`F2-NOAUTH`, `N2-INVALID`, `N3-EMPTY`, `G2-QUOTA-LOW`) and exit codes (e.g.
52+
`3` = `ExitNotInitialized`) are part of the tool's contract. Don't rename
53+
or renumber them — scripts and docs key off the literal strings.
54+
55+
## `skill/SKILL.md`
56+
57+
This file is runtime instructions read by coding agents, not just
58+
documentation. Its semantics (what it tells an agent to do, and when) must
59+
not drift casually — treat behavioral changes there with the same care as a
60+
CLI flag change.

CHANGELOG.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Changelog
2+
3+
All notable changes to this project will be documented in this file.
4+
5+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7+
8+
## [Unreleased]
9+
10+
### Added
11+
12+
- Initial release of opendoc: one-way mirroring of authorized Notion and
13+
Feishu/Lark documents into a local, read-only Markdown tree.
14+
- Incremental sync with full-reconciliation rounds, delete/move tracking,
15+
and a permission-flap guard.
16+
- Content-addressed asset pool, two-phase internal-link rewriting, and an
17+
auto-generated `INDEX.md` library map.
18+
- Embedded Feishu engine (no external CLI or Node runtime required);
19+
Notion via the official API with a read-only integration token.
20+
- Agent-first CLI: `init` / `sync` / `status` / `doctor` / `resolve` /
21+
`schedule`, with structured `--json` output, deterministic exit codes,
22+
and stable doctor failure codes.
23+
- Claude Code plugin (`skill/`) that wraps the engine and teaches agents
24+
how to retrieve from the mirror.

0 commit comments

Comments
 (0)