Skip to content
Closed
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
106 changes: 106 additions & 0 deletions .github/workflows/apply-changeset.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
name: Knowledge Distillery — Apply Changeset

on:
pull_request:
types: [closed]
branches: [main, master]

jobs:
apply-changeset:
if: >-
github.event.pull_request.merged &&
startsWith(github.event.pull_request.head.ref, 'knowledge/batch-')
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v6
with:
ref: ${{ github.event.pull_request.base.ref }}
fetch-depth: 0

- name: Checkout Knowledge Distillery plugin
uses: actions/checkout@v6
with:
repository: ether-moon/knowledge-distillery
ref: main
path: .knowledge-distillery-plugin

- name: Configure git identity
run: |
git config user.name "knowledge-distillery[bot]"
git config user.email "knowledge-distillery[bot]@users.noreply.github.com"

- name: Extract batch date from branch name
id: batch
env:
BRANCH: ${{ github.event.pull_request.head.ref }}
run: |
if [[ ! "$BRANCH" =~ ^knowledge/batch-([0-9]{4}-[0-9]{2}-[0-9]{2})(-[0-9]+)?$ ]]; then
echo "::error::Unexpected branch format: ${BRANCH}"
exit 1
fi
DATE="${BASH_REMATCH[1]}"
echo "date=${DATE}" >> "$GITHUB_OUTPUT"
echo "Batch date: ${DATE}"

- name: Find and apply changeset
run: |
GATE=$(find .knowledge-distillery-plugin -name knowledge-gate -path '*/scripts/*' -type f | head -1)
if [ -z "$GATE" ]; then
echo "::error::knowledge-gate script not found in plugin checkout"
exit 1
fi
chmod +x "$GATE"

CHANGESET=".knowledge/changesets/batch-${{ steps.batch.outputs.date }}.json"

if [ ! -f "$CHANGESET" ]; then
echo "::warning::No changeset file found at ${CHANGESET} — skipping"
exit 0
fi

ACCEPTED=$(jq '[.entries[] | select(.status == "accepted")] | length' "$CHANGESET")
echo "Accepted entries to apply: ${ACCEPTED}"

if [ "$ACCEPTED" -eq 0 ]; then
echo "No accepted entries — skipping vault update"
exit 0
fi

"$GATE" _changeset-apply "$CHANGESET"

- name: Commit and push vault.db
run: |
if git diff --quiet .knowledge/vault.db 2>/dev/null; then
echo "No vault.db changes — skipping commit"
exit 0
fi

git add .knowledge/vault.db
git commit -m "knowledge: apply batch ${{ steps.batch.outputs.date }} changeset"
git push origin ${{ github.event.pull_request.base.ref }}

- name: Clean up batch artifacts
env:
BATCH_DATE: ${{ steps.batch.outputs.date }}
run: |
CHANGESET=".knowledge/changesets/batch-${BATCH_DATE}.json"
REPORT=".knowledge/reports/batch-${BATCH_DATE}.md"
CHANGED=false

if [ -f "$CHANGESET" ]; then
git rm "$CHANGESET"
CHANGED=true
fi

if [ -f "$REPORT" ]; then
git rm "$REPORT"
CHANGED=true
fi

if [ "$CHANGED" = true ]; then
git pull --rebase origin ${{ github.event.pull_request.base.ref }}
git commit -m "knowledge: clean up batch ${BATCH_DATE} artifacts"
git push origin ${{ github.event.pull_request.base.ref }}
fi
98 changes: 98 additions & 0 deletions .github/workflows/batch-refine.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
name: Knowledge Distillery — Batch Refine

on:
schedule:
- cron: '0 0 * * 1' # Every Monday 09:00 KST (00:00 UTC)
workflow_dispatch:

jobs:
collect-and-refine:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
issues: write
id-token: write
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0

- name: Checkout Knowledge Distillery plugin
uses: actions/checkout@v6
with:
repository: ether-moon/knowledge-distillery
ref: main
path: .knowledge-distillery-plugin

- name: Write dynamic MCP config
run: |
if [ -n "${{ secrets.LINEAR_API_KEY }}" ]; then echo "::add-mask::${{ secrets.LINEAR_API_KEY }}"; fi
if [ -n "${{ secrets.SLACK_API_KEY }}" ]; then echo "::add-mask::${{ secrets.SLACK_API_KEY }}"; fi
if [ -n "${{ secrets.NOTION_API_KEY }}" ]; then echo "::add-mask::${{ secrets.NOTION_API_KEY }}"; fi
cat > .mcp.json << 'MCPEOF'
{
"mcpServers": {
"github": {
"type": "http",
"url": "https://api.githubcopilot.com/mcp/",
"headers": {
"Authorization": "Bearer ${{ secrets.GITHUB_TOKEN }}",
"X-MCP-Toolsets": "pull_requests,issues,labels"
}
},
"linear": {
"type": "stdio",
"command": "npx",
"args": ["-y", "mcp-linear"],
"env": {
"LINEAR_API_KEY": "${{ secrets.LINEAR_API_KEY }}"
}
},
"slack": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-slack"],
"env": {
"SLACK_BOT_TOKEN": "${{ secrets.SLACK_API_KEY }}"
}
},
"notion": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@notionhq/notion-mcp-server"],
"env": {
"OPENAPI_MCP_HEADERS": "{\"Authorization\": \"Bearer ${{ secrets.NOTION_API_KEY }}\", \"Notion-Version\": \"2022-06-28\"}"
}
}
}
}
MCPEOF

- name: Configure git identity
run: |
git config user.name "${{ github.actor }}"
git config user.email "${{ github.actor }}@users.noreply.github.com"

- uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
prompt: |
Use skill /knowledge-distillery:batch-refine.
Find all PRs with 'knowledge:pending' label,
collect evidence using each PR's Evidence Bundle Manifest, run refinement pipeline,
write accepted entries to a changeset file.
Naming conventions (MUST follow exactly):
- Report branch: knowledge/batch-YYYY-MM-DD (e.g. knowledge/batch-2026-03-27)
- Changeset file: .knowledge/changesets/batch-YYYY-MM-DD.json
- Only entries with .entries[].status == "accepted" are included
On success: update label to 'knowledge:collected'.
On insufficient evidence: leave label as 'knowledge:pending' and report the reason.
Create a Report PR with change summary.
Do NOT modify vault.db directly — the changeset will be applied on merge.
claude_args: "--plugin-dir .knowledge-distillery-plugin --allowedTools 'mcp__github__*,mcp__linear__*,mcp__slack__*,mcp__notion__*,Bash(*),Read(*),Write(*),Glob(*),Grep(*),Skill(*),Agent(*)'"
show_full_output: true

- name: Cleanup sensitive files
if: always()
run: rm -f .mcp.json
94 changes: 94 additions & 0 deletions .github/workflows/curate-report.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
name: Knowledge Distillery — Curate Report

on:
issue_comment:
types: [created]

jobs:
curate-report:
if: >-
github.event.issue.pull_request &&
contains(github.event.comment.body, '/curate') &&
contains(fromJSON('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association)
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
issues: write
id-token: write
steps:
- name: Get PR details
id: pr
uses: actions/github-script@v7
with:
script: |
const pr = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.issue.number
});
const branch = pr.data.head.ref;
if (!branch.startsWith('knowledge/batch-')) {
core.notice('Skipping: not a Report PR branch (' + branch + ')');
core.setOutput('skip', 'true');
return;
}
core.setOutput('skip', 'false');
core.setOutput('branch', branch);
core.setOutput('pr_number', context.issue.number);

- uses: actions/checkout@v6
if: steps.pr.outputs.skip != 'true'
with:
ref: ${{ steps.pr.outputs.branch }}
fetch-depth: 0

- name: Checkout Knowledge Distillery plugin
if: steps.pr.outputs.skip != 'true'
uses: actions/checkout@v6
with:
repository: ether-moon/knowledge-distillery
ref: main
path: .knowledge-distillery-plugin

- name: Write dynamic MCP config
if: steps.pr.outputs.skip != 'true'
run: |
cat > .mcp.json << 'MCPEOF'
{
"mcpServers": {
"github": {
"type": "http",
"url": "https://api.githubcopilot.com/mcp/",
"headers": {
"Authorization": "Bearer ${{ secrets.GITHUB_TOKEN }}",
"X-MCP-Toolsets": "pull_requests,issues"
}
}
}
}
MCPEOF

- name: Configure git identity
if: steps.pr.outputs.skip != 'true'
run: |
git config user.name "${{ github.actor }}"
git config user.email "${{ github.actor }}@users.noreply.github.com"

- uses: anthropics/claude-code-action@v1
if: steps.pr.outputs.skip != 'true'
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
prompt: |
Use skill /knowledge-distillery:curate-report.
Process reviewer feedback on Report PR #${{ steps.pr.outputs.pr_number }}
(branch: ${{ steps.pr.outputs.branch }}).
Read all PR comments, classify feedback into reject/update/keep actions,
update the changeset file (.knowledge/changesets/), regenerate the batch report, commit, and post summary.
Do NOT modify vault.db directly — operate on the changeset file only.
claude_args: "--plugin-dir .knowledge-distillery-plugin --allowedTools 'mcp__github__*,Bash(*),Read(*),Write(*),Glob(*),Grep(*),Skill(*),Agent(*)'"
show_full_output: true

- name: Cleanup sensitive files
if: always() && steps.pr.outputs.skip != 'true'
run: rm -f .mcp.json
69 changes: 69 additions & 0 deletions .github/workflows/mark-evidence.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
name: Knowledge Distillery — Mark Evidence

on:
pull_request:
types: [closed]
branches: [main, master]

jobs:
mark-evidence:
if: >-
github.event.pull_request.merged == true &&
!startsWith(github.event.pull_request.head.ref, 'knowledge/batch-')
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
issues: write
id-token: write
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0

- name: Checkout Knowledge Distillery plugin
uses: actions/checkout@v6
with:
repository: ether-moon/knowledge-distillery
ref: main
path: .knowledge-distillery-plugin

- name: Write dynamic MCP config
run: |
if [ -n "${{ secrets.LINEAR_API_KEY }}" ]; then echo "::add-mask::${{ secrets.LINEAR_API_KEY }}"; fi
cat > .mcp.json << 'MCPEOF'
{
"mcpServers": {
"github": {
"type": "http",
"url": "https://api.githubcopilot.com/mcp/",
"headers": {
"Authorization": "Bearer ${{ secrets.GITHUB_TOKEN }}",
"X-MCP-Toolsets": "pull_requests,issues,labels"
}
},
"linear": {
"type": "stdio",
"command": "npx",
"args": ["-y", "mcp-linear"],
"env": {
"LINEAR_API_KEY": "${{ secrets.LINEAR_API_KEY }}"
}
}
}
}
MCPEOF

- uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
prompt: |
Use skill /knowledge-distillery:mark-evidence for PR #${{ github.event.pull_request.number }}.
Extract evidence identifiers, write Evidence Bundle Manifest as PR comment,
and add 'knowledge:pending' label.
claude_args: "--plugin-dir .knowledge-distillery-plugin --allowedTools 'mcp__github__*,mcp__linear__*,Bash(*),Read(*),Glob(*),Grep(*),Skill(*),Agent(*)'"
show_full_output: true

- name: Cleanup sensitive files
if: always()
run: rm -f .mcp.json
10 changes: 10 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
.DS_Store
node_modules/
.claude/

# Knowledge Distillery — vault is committed as binary, reports are committed
# Only ignore temporary/working files
.knowledge/tmp/

# Vault usage tracking (consumed and cleared by memento-commit)
tmp/

# Dynamic MCP config — contains secrets at runtime, must never be committed
.mcp.json
Binary file added .knowledge/vault.db
Binary file not shown.
Loading