Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/release-please.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ jobs:
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add Cargo.toml crates/origin-mcp/npm/package.json crates/origin-cli/npm/package.json plugin/.claude-plugin/plugin.json plugin/bin/origin-mcp-runner.sh plugin/skills/init/SKILL.md
git add Cargo.toml Cargo.lock crates/origin-mcp/npm/package.json crates/origin-cli/npm/package.json plugin/.claude-plugin/plugin.json plugin/bin/origin-mcp-runner.sh plugin/skills/init/SKILL.md
if ! git diff --cached --quiet; then
git commit -m "chore: sync versions to $(cat version.txt | tr -d '[:space:]')"
git push origin HEAD
Expand Down
10 changes: 5 additions & 5 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ repository = "https://github.com/7xuanlu/origin"
[workspace.dependencies]
# Internal crates — both path AND version required for cargo publish
origin-types = { path = "crates/origin-types", version = "0.6.1" }
origin-core = { path = "crates/origin-core", version = "0.6.0" }
origin-core = { path = "crates/origin-core", version = "0.6.1" }

# Serialization
serde = { version = "1", features = ["derive"] }
Expand Down
16 changes: 9 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ npx -y @7xuanlu/origin setup
```

That installs the `origin` CLI, `origin-server` daemon, and `origin-mcp` connector into `~/.origin/bin/`, configures local memory, registers the daemon with launchd, and verifies status.
CLI details: [crates/origin-cli](crates/origin-cli/README.md).
For terminal use, start with `origin status`, `origin recall <query>`, or `origin store <text>`. CLI details: [crates/origin-cli](crates/origin-cli/README.md).

Then add the MCP connector to Cursor, Codex, Claude Desktop, Gemini CLI, or any client that accepts a JSON `mcpServers` entry:

Expand All @@ -64,13 +64,15 @@ The `origin-mcp` connector runs on demand and talks to the local Origin daemon f

## How Origin works

Origin follows the rhythm of an AI work session.
Origin follows the rhythm of an AI work session, with five verbs you use directly:

1. **Session starts** — your agent loads relevant project context, recent handoffs, decisions, and pages.
2. **During work** — save durable decisions, lessons, gotchas, and project facts in chat.
3. **Session ends** — write a handoff so the next run knows what changed and where to continue.
4. **Between sessions** — Origin deduplicates, links related ideas, distills wiki pages, and keeps provenance attached.
5. **Next session** — context comes back through the Claude Code plugin or `origin-mcp`, without replaying full chat history.
1. **Session starts** — `/brief [topic]` loads project status, identity, preferences, and topic-relevant memories so the agent walks in with context.
2. **During work** — `/capture <thing>` saves a decision, lesson, gotcha, or project fact in flow. `/recall <query>` looks anything up.
3. **Session ends** — `/handoff` writes what changed, what's still open, and where to continue, so the next run picks up cleanly.
4. **Between sessions** — the daemon deduplicates overlapping captures and links related ideas in the background. `/distill` synthesizes wiki pages from clusters of related memories when you want a deliberate pass.
5. **Next session** — `/brief` brings it all back through the plugin or `origin-mcp`, without replaying full chat history.

Full skill reference: [plugin/skills](plugin/skills/README.md).

No cloud sync or telemetry by default. Local models and Anthropic keys are opt-in.

Expand Down
4 changes: 3 additions & 1 deletion plugin/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@
"license": "Apache-2.0",
"category": "memory",
"keywords": [
"claude-code",
"memory",
"knowledge",
"context",
"recall",
"mcp"
"mcp",
"local-first"
]
}
4 changes: 2 additions & 2 deletions scripts/bump-version.sh
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ echo " Updated Cargo.toml (workspace.package.version)"
# `version = "0.X.Y"` against a workspace.package "0.X.Z" and the build fails.
for dep in origin-types origin-core; do
if [[ "$(uname)" == "Darwin" ]]; then
sed -i '' -E "s|^(${dep}[[:space:]]+= \\{ path = \"crates/${dep}\", version = \")[^\"]+(\".*)|\\1${NEW_VERSION}\\2|" Cargo.toml
sed -i '' -E "s|^(${dep}[[:space:]]+= \\{ path = \"crates/${dep}\",[[:space:]]+version = \")[^\"]+(\".*)|\\1${NEW_VERSION}\\2|" Cargo.toml
else
sed -i -E "s|^(${dep}[[:space:]]+= \\{ path = \"crates/${dep}\", version = \")[^\"]+(\".*)|\\1${NEW_VERSION}\\2|" Cargo.toml
sed -i -E "s|^(${dep}[[:space:]]+= \\{ path = \"crates/${dep}\",[[:space:]]+version = \")[^\"]+(\".*)|\\1${NEW_VERSION}\\2|" Cargo.toml
fi
done
echo " Updated Cargo.toml (workspace.dependencies origin-types/origin-core)"
Expand Down
8 changes: 8 additions & 0 deletions scripts/bump-version.test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ EOF
cat > "$TMPDIR_TEST/Cargo.toml" <<EOF
[workspace.package]
version = "0.4.1" # x-release-please-version

[workspace.dependencies]
origin-types = { path = "crates/origin-types", version = "0.4.1" }
origin-core = { path = "crates/origin-core", version = "0.4.1" }
EOF

cat > "$TMPDIR_TEST/crates/origin-mcp/npm/package.json" <<EOF
Expand Down Expand Up @@ -47,11 +51,15 @@ EOF

# Assert all manifests bumped to 0.5.0
WS_VER=$(grep -E '^version = ' "$TMPDIR_TEST/Cargo.toml" | sed -E 's/version = "([^"]+)".*/\1/')
ORIGIN_TYPES_DEP_VER=$(grep -E '^origin-types[[:space:]]+=' "$TMPDIR_TEST/Cargo.toml" | sed -E 's/.*version = "([^"]+)".*/\1/')
ORIGIN_CORE_DEP_VER=$(grep -E '^origin-core[[:space:]]+=' "$TMPDIR_TEST/Cargo.toml" | sed -E 's/.*version = "([^"]+)".*/\1/')
MCP_NPM_VER=$(jq -r .version "$TMPDIR_TEST/crates/origin-mcp/npm/package.json")
ORIGIN_NPM_VER=$(jq -r .version "$TMPDIR_TEST/crates/origin-cli/npm/package.json")
PLUGIN_VER=$(jq -r .version "$TMPDIR_TEST/plugin/.claude-plugin/plugin.json")

[[ "$WS_VER" == "0.5.0" ]] || { echo "FAIL: Cargo.toml not bumped (got $WS_VER)"; exit 1; }
[[ "$ORIGIN_TYPES_DEP_VER" == "0.5.0" ]] || { echo "FAIL: origin-types dep not bumped (got $ORIGIN_TYPES_DEP_VER)"; exit 1; }
[[ "$ORIGIN_CORE_DEP_VER" == "0.5.0" ]] || { echo "FAIL: origin-core dep not bumped (got $ORIGIN_CORE_DEP_VER)"; exit 1; }
[[ "$MCP_NPM_VER" == "0.5.0" ]] || { echo "FAIL: origin-mcp npm not bumped (got $MCP_NPM_VER)"; exit 1; }
[[ "$ORIGIN_NPM_VER" == "0.5.0" ]] || { echo "FAIL: @7xuanlu/origin npm not bumped (got $ORIGIN_NPM_VER)"; exit 1; }
[[ "$PLUGIN_VER" == "0.5.0" ]] || { echo "FAIL: plugin not bumped (got $PLUGIN_VER)"; exit 1; }
Expand Down
31 changes: 30 additions & 1 deletion scripts/validate-versions.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,49 @@ TAG_VER="${RELEASE_TAG#v}"

VTXT_VER=$(cat version.txt | tr -d '[:space:]')
WS_VER=$(grep -E '^version = ' Cargo.toml | head -1 | sed -E 's/version = "([^"]+)".*/\1/')
ORIGIN_TYPES_DEP_VER=$(grep -E '^origin-types[[:space:]]+=' Cargo.toml | sed -E 's/.*version = "([^"]+)".*/\1/')
ORIGIN_CORE_DEP_VER=$(grep -E '^origin-core[[:space:]]+=' Cargo.toml | sed -E 's/.*version = "([^"]+)".*/\1/')
LOCK_VERSIONS=$(awk '
$0 == "[[package]]" { in_pkg=1; name=""; version=""; next }
in_pkg && $1 == "name" && $2 == "=" {
name=$3
gsub(/"/, "", name)
next
}
in_pkg && $1 == "version" && $2 == "=" {
version=$3
gsub(/"/, "", version)
if (name == "origin" || name == "origin-core" || name == "origin-mcp" || name == "origin-server" || name == "origin-types") {
print name ":" version
}
in_pkg=0
}
' Cargo.lock | sort)
MCP_NPM_VER=$(jq -r .version crates/origin-mcp/npm/package.json)
ORIGIN_NPM_VER=$(jq -r .version crates/origin-cli/npm/package.json)
PLUGIN_VER=$(jq -r .version plugin/.claude-plugin/plugin.json)

echo "Tag: $TAG_VER"
echo "version.txt: $VTXT_VER"
echo "Cargo: $WS_VER"
echo "origin-types dep: $ORIGIN_TYPES_DEP_VER"
echo "origin-core dep: $ORIGIN_CORE_DEP_VER"
echo "Cargo.lock:"
printf '%s\n' "$LOCK_VERSIONS" | sed 's/^/ /'
echo "origin-mcp npm: $MCP_NPM_VER"
echo "@7xuanlu/origin npm: $ORIGIN_NPM_VER"
echo "Plugin: $PLUGIN_VER"

if [[ "$VTXT_VER" != "$TAG_VER" || "$WS_VER" != "$TAG_VER" || "$MCP_NPM_VER" != "$TAG_VER" || "$ORIGIN_NPM_VER" != "$TAG_VER" || "$PLUGIN_VER" != "$TAG_VER" ]]; then
if [[ "$VTXT_VER" != "$TAG_VER" || "$WS_VER" != "$TAG_VER" || "$ORIGIN_TYPES_DEP_VER" != "$TAG_VER" || "$ORIGIN_CORE_DEP_VER" != "$TAG_VER" || "$MCP_NPM_VER" != "$TAG_VER" || "$ORIGIN_NPM_VER" != "$TAG_VER" || "$PLUGIN_VER" != "$TAG_VER" ]]; then
echo "ERROR: version drift — bump-version.sh likely failed in release-please.yml"
exit 1
fi

for crate in origin origin-core origin-mcp origin-server origin-types; do
if ! printf '%s\n' "$LOCK_VERSIONS" | grep -qx "${crate}:${TAG_VER}"; then
echo "ERROR: Cargo.lock drift — ${crate} is not ${TAG_VER}"
exit 1
fi
done

echo "All versions consistent: $TAG_VER"
43 changes: 43 additions & 0 deletions scripts/validate-versions.test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,31 @@ echo "0.5.0" > "$TMPDIR_TEST/version.txt"
cat > "$TMPDIR_TEST/Cargo.toml" <<EOF
[workspace.package]
version = "0.5.0" # x-release-please-version

[workspace.dependencies]
origin-types = { path = "crates/origin-types", version = "0.5.0" }
origin-core = { path = "crates/origin-core", version = "0.5.0" }
EOF
cat > "$TMPDIR_TEST/Cargo.lock" <<EOF
[[package]]
name = "origin"
version = "0.5.0"

[[package]]
name = "origin-core"
version = "0.5.0"

[[package]]
name = "origin-mcp"
version = "0.5.0"

[[package]]
name = "origin-server"
version = "0.5.0"

[[package]]
name = "origin-types"
version = "0.5.0"
EOF
echo '{"version": "0.5.0"}' > "$TMPDIR_TEST/crates/origin-mcp/npm/package.json"
echo '{"version": "0.5.0"}' > "$TMPDIR_TEST/crates/origin-cli/npm/package.json"
Expand All @@ -25,3 +50,21 @@ if (cd "$TMPDIR_TEST" && RELEASE_TAG="v0.5.0" bash "$OLDPWD/scripts/validate-ver
exit 1
fi
echo "PASS test 2: drift detected"

# Test 3: internal workspace dependency mismatch → exit 1
echo '{"version": "0.5.0"}' > "$TMPDIR_TEST/plugin/.claude-plugin/plugin.json"
perl -0pi -e 's/origin-core = \{ path = "crates\/origin-core", version = "0\.5\.0" \}/origin-core = { path = "crates\/origin-core", version = "0.4.9" }/' "$TMPDIR_TEST/Cargo.toml"
if (cd "$TMPDIR_TEST" && RELEASE_TAG="v0.5.0" bash "$OLDPWD/scripts/validate-versions.sh") 2>/dev/null; then
echo "FAIL test 3: should have detected internal dependency drift"
exit 1
fi
echo "PASS test 3: internal dependency drift detected"

# Test 4: Cargo.lock mismatch → exit 1
perl -0pi -e 's/origin-core = \{ path = "crates\/origin-core", version = "0\.4\.9" \}/origin-core = { path = "crates\/origin-core", version = "0.5.0" }/' "$TMPDIR_TEST/Cargo.toml"
perl -0pi -e 's/name = "origin-core"\nversion = "0\.5\.0"/name = "origin-core"\nversion = "0.4.9"/' "$TMPDIR_TEST/Cargo.lock"
if (cd "$TMPDIR_TEST" && RELEASE_TAG="v0.5.0" bash "$OLDPWD/scripts/validate-versions.sh") 2>/dev/null; then
echo "FAIL test 4: should have detected Cargo.lock drift"
exit 1
fi
echo "PASS test 4: Cargo.lock drift detected"
Loading