Created
January 21, 2026 04:42
-
-
Save twiecki/26f2423e69cb6ee6372d49938cb38842 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Personal Knowledge Daemon - Fresh Template Setup | |
| You are setting up a fresh personal knowledge management system following the "daemon" pattern - a persistent memory layer for Claude Code stored as markdown files in Git. | |
| ## Core Concept | |
| **GitHub = Memory | Markdown = Thoughts | PRs = Memory Updates** | |
| Each Claude Code session: | |
| 1. Reads context from markdown files | |
| 2. Works on tasks, updates knowledge | |
| 3. Commits changes via PR | |
| 4. Next session picks up where you left off | |
| ## Directory Structure to Create | |
| ``` | |
| daemon/ | |
| ├── README.md # Repository overview and orientation guide | |
| ├── AGENTS.md # Agent workflow documentation | |
| ├── pyproject.toml # Python dependencies (use uv) | |
| ├── .gitignore # Standard Python + secrets | |
| ├── .env.example # Template for API keys | |
| │ | |
| ├── skills/ # Composio integrations and tools | |
| │ ├── composio-overview.md # Quick start guide for Composio | |
| │ ├── composio-calendar.md # Google Calendar integration | |
| │ ├── composio-gmail.md # Gmail integration | |
| │ ├── composio-drive.md # Google Drive integration | |
| │ └── ... (add more as needed) | |
| │ | |
| ├── hooks/ # Claude Code lifecycle hooks | |
| │ ├── session-start.sh # SessionStart hook (install tools, clone repos) | |
| │ └── subagent-pr.sh # SubagentStop hook (auto PR creation) | |
| │ | |
| ├── settings.json # Claude Code settings (hooks config) | |
| │ | |
| ├── tasks/ | |
| │ ├── active.md # Current priorities and TODOs | |
| │ └── archive/ # Completed tasks | |
| │ | |
| ├── people/ # Relationship profiles (optional) | |
| │ | |
| ├── work/ # Professional context (optional) | |
| │ └── buckets/ # Open work items | |
| │ | |
| ├── personal/ # Personal context (optional) | |
| │ | |
| └── projects/ # Git submodules or cloned repos (optional) | |
| ``` | |
| ## Setup Steps | |
| ### 1. Create README.md | |
| ```markdown | |
| # Daemon - Personal Knowledge System | |
| A persistent memory layer for Claude, stored as markdown files in Git. | |
| ## How It Works | |
| 1. **Spawn**: Start a Claude Code session with this repo | |
| 2. **Context**: Claude reads relevant files to understand the current situation | |
| 3. **Work**: Discuss, explore, plan - Claude updates markdown files with new insights | |
| 4. **Commit**: Create a PR, merge it, memory is updated | |
| 5. **Persist**: Next session picks up where you left off | |
| ## Directory Structure | |
| [Copy the tree structure from above] | |
| ## Getting Started | |
| 1. Set up `.env` file with API keys (see `.env.example`) | |
| 2. Start a Claude Code session | |
| 3. The SessionStart hook will install tools and clone any configured repos | |
| 4. Start working - all context is in markdown files | |
| ## Language & Communication | |
| - Files: English (for portability and tooling) | |
| - Conversation: [Your preference - German/English/etc] | |
| ## Skills | |
| Available integrations via `skills/`: | |
| - Calendar (Google Calendar via Composio) | |
| - Email (Gmail via Composio) | |
| - [Add your integrations] | |
| See `skills/composio-overview.md` for setup instructions. | |
| ``` | |
| ### 2. Create AGENTS.md | |
| ```markdown | |
| # Agent Workflow & Orchestration | |
| ## Overview | |
| This repo supports a hierarchical agent workflow: | |
| ``` | |
| Main Branch: claude/main-session-xxxxx | |
| └── Orchestrator-Branch (session with full context) | |
| └── Sub-Agent-Branch (specialized task) | |
| → PR back to Orchestrator-Branch | |
| ``` | |
| **Orchestrator**: Main session with full context, starts specialized sub-agents | |
| **Sub-Agent**: Focused task, reports back to orchestrator | |
| ## Branch Naming Convention | |
| All branches must follow: `claude/<description>-<session-id>` | |
| Examples: | |
| - `claude/main-session-HOaw1` | |
| - `claude/email-summary-task-xY3k9` | |
| ## Environment Variables for Sub-Agents | |
| When starting a sub-agent from an orchestrator session: | |
| ```bash | |
| export PARENT_BRANCH=$(git branch --show-current) | |
| # Then spawn sub-agent | |
| ``` | |
| The `PARENT_BRANCH` env var tells the SubagentStop hook to create a PR against the orchestrator branch instead of main. | |
| ## Git Operations | |
| ### Push Requirements | |
| - Always use: `git push -u origin <branch-name>` | |
| - Branch must match pattern: `claude/*-<session-id>` | |
| - Retry on network errors: up to 4 times with exponential backoff (2s, 4s, 8s, 16s) | |
| ### Fetch/Pull | |
| - Prefer specific branches: `git fetch origin <branch-name>` | |
| - Retry on network errors: same exponential backoff | |
| ## Workflow Hooks | |
| ### SessionStart Hook | |
| - Installs required tools (gh CLI, etc.) | |
| - Loads environment variables from `.env` | |
| - Clones configured repos to `projects/` | |
| - Sets up authentication | |
| ### SubagentStop Hook | |
| - Automatically creates PR when sub-agent completes | |
| - PR target: `$PARENT_BRANCH` (if set) or main branch | |
| - Enables auto-merge if repository supports it | |
| - Waits for CI checks | |
| - Merges if all checks pass | |
| ## Python Dependency Management | |
| Use `uv` (not `pip`): | |
| ```bash | |
| # Install/sync dependencies | |
| uv sync | |
| # Add new package | |
| uv add <package-name> | |
| # Run script (uses .venv automatically) | |
| uv run python script.py | |
| ``` | |
| Dependencies defined in `pyproject.toml`. | |
| ## GitHub CLI | |
| Always load environment variables first: | |
| ```bash | |
| source /home/user/daemon/.env && export GH_TOKEN="$GITHUB_TOKEN" && gh <command> | |
| ``` | |
| This is required because hooks cannot pass environment variables to main session. | |
| ``` | |
| ### 3. Create settings.json | |
| ```json | |
| { | |
| "$schema": "https://json.schemastore.org/claude-code-settings.json", | |
| "hooks": { | |
| "SessionStart": [ | |
| { | |
| "matcher": "", | |
| "hooks": [ | |
| { | |
| "type": "command", | |
| "command": "hooks/session-start.sh" | |
| } | |
| ] | |
| } | |
| ], | |
| "SubagentStop": [ | |
| { | |
| "matcher": "", | |
| "hooks": [ | |
| { | |
| "type": "command", | |
| "command": "hooks/subagent-pr.sh" | |
| } | |
| ] | |
| } | |
| ] | |
| } | |
| } | |
| ``` | |
| ### 4. Create pyproject.toml | |
| ```toml | |
| [project] | |
| name = "daemon" | |
| version = "0.1.0" | |
| description = "Personal assistant daemon" | |
| requires-python = ">=3.11" | |
| dependencies = [ | |
| "composio", | |
| "python-dotenv", | |
| ] | |
| [tool.uv] | |
| dev-dependencies = [] | |
| ``` | |
| ### 5. Create .gitignore | |
| ``` | |
| # Python | |
| __pycache__/ | |
| *.py[cod] | |
| *$py.class | |
| .venv/ | |
| venv/ | |
| ENV/ | |
| env/ | |
| *.so | |
| .Python | |
| build/ | |
| develop-eggs/ | |
| dist/ | |
| downloads/ | |
| eggs/ | |
| .eggs/ | |
| lib/ | |
| lib64/ | |
| parts/ | |
| sdist/ | |
| var/ | |
| wheels/ | |
| *.egg-info/ | |
| .installed.cfg | |
| *.egg | |
| # Environment | |
| .env | |
| .env.local | |
| # IDEs | |
| .vscode/ | |
| .idea/ | |
| *.swp | |
| *.swo | |
| *~ | |
| # OS | |
| .DS_Store | |
| Thumbs.db | |
| # Logs | |
| *.log | |
| # Claude Code | |
| .claude/cache/ | |
| ``` | |
| ### 6. Create .env.example | |
| ```bash | |
| # Composio API Key (get from https://app.composio.dev) | |
| COMPOSIO_API_KEY=your_composio_api_key_here | |
| # GitHub Token (for gh CLI authentication) | |
| GITHUB_TOKEN=your_github_token_here | |
| # Optional: Claude Instance ID (for multi-instance coordination) | |
| CLAUDE_INSTANCE=A | |
| ``` | |
| ### 7. Create hooks/session-start.sh | |
| ```bash | |
| #!/bin/bash | |
| # SessionStart hook: setup environment and tools | |
| SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" | |
| REPO_DIR="$SCRIPT_DIR/.." | |
| ENV_FILE="$REPO_DIR/.env" | |
| # Load environment variables | |
| if [ -f "$ENV_FILE" ]; then | |
| set -a | |
| source "$ENV_FILE" | |
| set +a | |
| fi | |
| # Set Claude instance ID | |
| export CLAUDE_INSTANCE="${CLAUDE_INSTANCE:-A}" | |
| # Install GitHub CLI if not present | |
| if ! command -v gh &> /dev/null; then | |
| echo "Installing GitHub CLI..." | |
| GH_VERSION="2.63.2" | |
| if curl -fsSL "https://github.com/cli/cli/releases/download/v${GH_VERSION}/gh_${GH_VERSION}_linux_amd64.tar.gz" -o /tmp/gh.tar.gz && \ | |
| tar -xzf /tmp/gh.tar.gz -C /tmp && \ | |
| sudo mv "/tmp/gh_${GH_VERSION}_linux_amd64/bin/gh" /usr/local/bin/ && \ | |
| rm -rf /tmp/gh.tar.gz /tmp/gh_${GH_VERSION}_linux_amd64; then | |
| echo "GitHub CLI installed." | |
| else | |
| echo "GitHub CLI installation failed." | |
| fi | |
| fi | |
| # Set GH_TOKEN for gh CLI authentication | |
| if [ -n "$GITHUB_TOKEN" ]; then | |
| export GH_TOKEN="$GITHUB_TOKEN" | |
| fi | |
| # Optional: Clone project repos | |
| # PROJECTS_DIR="$REPO_DIR/projects" | |
| # if [ -d "$PROJECTS_DIR" ]; then | |
| # echo "Checking project repos..." | |
| # REPOS="your-org/repo1 your-org/repo2" | |
| # for repo in $REPOS; do | |
| # repo_name=$(basename $repo) | |
| # if [ ! -d "$PROJECTS_DIR/$repo_name/.git" ]; then | |
| # echo "Cloning $repo..." | |
| # gh repo clone "$repo" "$PROJECTS_DIR/$repo_name" 2>/dev/null || \ | |
| # echo "Failed to clone $repo" | |
| # fi | |
| # done | |
| # fi | |
| echo "Session ready!" | |
| ``` | |
| ### 8. Create hooks/subagent-pr.sh | |
| ```bash | |
| #!/bin/bash | |
| # SubagentStop hook: automatic PR creation and merge | |
| set -e | |
| SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" | |
| REPO_DIR="$SCRIPT_DIR/.." | |
| cd "$REPO_DIR" | |
| # Load environment for gh CLI | |
| if [ -f "$REPO_DIR/.env" ]; then | |
| set -a | |
| source "$REPO_DIR/.env" | |
| set +a | |
| fi | |
| if [ -n "$GITHUB_TOKEN" ]; then | |
| export GH_TOKEN="$GITHUB_TOKEN" | |
| fi | |
| log() { | |
| echo "[PR-Workflow] $1" | |
| } | |
| # Current branch | |
| CURRENT_BRANCH=$(git branch --show-current) | |
| # Main branch (customize for your repo) | |
| MAIN_BRANCH="main" # Or "claude/main-session-xxxxx" if you have a long-lived orchestrator | |
| # Base branch for PR: PARENT_BRANCH (if set by orchestrator) or MAIN_BRANCH | |
| if [ -n "$PARENT_BRANCH" ]; then | |
| BASE_BRANCH="$PARENT_BRANCH" | |
| log "Sub-Agent Mode: PR against orchestrator branch $BASE_BRANCH" | |
| else | |
| BASE_BRANCH="$MAIN_BRANCH" | |
| log "Orchestrator Mode: PR against main branch $BASE_BRANCH" | |
| fi | |
| # Don't run on main branch | |
| if [[ "$CURRENT_BRANCH" == "$MAIN_BRANCH" ]]; then | |
| log "On main branch - skipping PR workflow" | |
| exit 0 | |
| fi | |
| # Don't run on base branch | |
| if [[ "$CURRENT_BRANCH" == "$BASE_BRANCH" ]]; then | |
| log "On base branch - skipping PR workflow" | |
| exit 0 | |
| fi | |
| # Check for uncommitted changes | |
| if ! git diff --quiet || ! git diff --cached --quiet; then | |
| log "WARNING: Uncommitted changes detected - these will NOT be in the PR" | |
| git status --short | |
| fi | |
| # Check if remote branch exists | |
| if ! git rev-parse --verify "origin/$CURRENT_BRANCH" >/dev/null 2>&1; then | |
| log "Branch $CURRENT_BRANCH doesn't exist on remote - pushing" | |
| HAS_NEW_COMMITS=true | |
| else | |
| # Check for unpushed commits | |
| LOCAL_COMMITS=$(git rev-list "origin/$CURRENT_BRANCH..$CURRENT_BRANCH" --count 2>/dev/null || echo "0") | |
| if [ "$LOCAL_COMMITS" -eq 0 ]; then | |
| log "No new commits to push" | |
| exit 0 | |
| fi | |
| HAS_NEW_COMMITS=true | |
| fi | |
| # Push to remote | |
| log "Pushing branch $CURRENT_BRANCH..." | |
| if ! git push -u origin "$CURRENT_BRANCH" 2>/dev/null; then | |
| log "Push failed - may already be pushed or insufficient permissions" | |
| fi | |
| # Check if PR already exists | |
| EXISTING_PR=$(gh pr list --head "$CURRENT_BRANCH" --json number --jq '.[0].number' 2>/dev/null || echo "") | |
| if [ -n "$EXISTING_PR" ] && [ "$EXISTING_PR" != "null" ]; then | |
| log "PR #$EXISTING_PR already exists for branch $CURRENT_BRANCH" | |
| PR_NUMBER="$EXISTING_PR" | |
| else | |
| # Create new PR | |
| log "Creating new PR..." | |
| COMMIT_MSG=$(git log -1 --pretty=%s) | |
| COMMIT_BODY=$(git log -1 --pretty=%b) | |
| PR_URL=$(gh pr create \ | |
| --title "$COMMIT_MSG" \ | |
| --body "${COMMIT_BODY:-Auto-created by SubagentStop workflow}" \ | |
| --base "$BASE_BRANCH" \ | |
| --head "$CURRENT_BRANCH" \ | |
| 2>/dev/null) || { | |
| log "PR creation failed" | |
| exit 1 | |
| } | |
| PR_NUMBER=$(echo "$PR_URL" | grep -oE '[0-9]+$') | |
| log "PR #$PR_NUMBER created: $PR_URL" | |
| fi | |
| # Enable auto-merge (if supported) | |
| log "Enabling auto-merge for PR #$PR_NUMBER..." | |
| gh pr merge "$PR_NUMBER" --auto --squash 2>/dev/null || { | |
| log "Auto-merge not available - manual merge required" | |
| } | |
| # Wait for CI checks | |
| log "Waiting for CI checks (max 5 minutes)..." | |
| if timeout 300 gh pr checks "$PR_NUMBER" --watch 2>/dev/null; then | |
| log "All checks passed!" | |
| # Manual merge if auto-merge wasn't enabled | |
| if ! gh pr view "$PR_NUMBER" --json autoMergeRequest --jq '.autoMergeRequest' | grep -q "SQUASH"; then | |
| log "Merging PR #$PR_NUMBER..." | |
| gh pr merge "$PR_NUMBER" --squash --delete-branch 2>/dev/null || { | |
| log "Merge failed - may need review" | |
| } | |
| else | |
| log "Auto-merge enabled - PR will merge automatically when ready" | |
| fi | |
| else | |
| log "CI checks failed or timeout - PR remains open" | |
| exit 1 | |
| fi | |
| log "Workflow complete!" | |
| ``` | |
| ### 9. Create tasks/active.md | |
| ```markdown | |
| # Active Tasks | |
| ## Current Priorities | |
| ### [Task Category] | |
| - [ ] Task 1 | |
| - [ ] Task 2 | |
| ## Waiting On / Blocked | |
| ## Notes | |
| ``` | |
| ### 10. Create skills/composio-overview.md | |
| ```markdown | |
| # Composio Integration Overview | |
| ## Quick Start | |
| ```python | |
| from composio import Composio | |
| from dotenv import load_dotenv | |
| import os | |
| load_dotenv('/home/user/daemon/.env') | |
| client = Composio(api_key=os.getenv('COMPOSIO_API_KEY')) | |
| ``` | |
| ## Setup Instructions | |
| 1. Get Composio API key from https://app.composio.dev | |
| 2. Add to `.env`: `COMPOSIO_API_KEY=your_key_here` | |
| 3. Connect services you need (Calendar, Gmail, Drive, etc.) | |
| 4. Note the `connected_account_id` for each service | |
| ## General Pattern | |
| ```python | |
| result = client.tools.execute( | |
| slug="TOOLNAME_ACTION", | |
| arguments={...}, | |
| connected_account_id="ca_XXX", # Use this, not user_id | |
| dangerously_skip_version_check=True # Required | |
| ) | |
| if result.get('successful'): | |
| data = result['data']['response_data'] | |
| else: | |
| error = result.get('error') | |
| ``` | |
| ## List Available Tools for a Service | |
| ```python | |
| tools = client.tools.get_raw_composio_tools(toolkits=["googlecalendar"]) | |
| for tool in tools: | |
| print(f"- {tool.slug}: {tool.name}") | |
| ``` | |
| ## List Connected Accounts | |
| ```python | |
| accounts = client.connected_accounts.list() | |
| for item in accounts.items: | |
| print(f"- {item.id}: {item.toolkit.slug} ({item.status})") | |
| ``` | |
| ## Common Issues | |
| ### SSL Certificate Errors | |
| Transient issue. Solution: Add `time.sleep(2)` and retry. | |
| ### Version Check Errors | |
| Always add `dangerously_skip_version_check=True` to execute() calls. | |
| ### User ID vs Connected Account ID | |
| - `user_id`: Links to a user, may have multiple connections | |
| - `connected_account_id`: Links to specific OAuth connection | |
| **Always prefer `connected_account_id` for reliability!** | |
| ``` | |
| ### 11. Make hooks executable | |
| ```bash | |
| chmod +x hooks/session-start.sh hooks/subagent-pr.sh | |
| ``` | |
| ### 12. Initialize git and create first commit | |
| ```bash | |
| git init | |
| git add . | |
| git commit -m "Initial daemon template setup" | |
| git branch -M main | |
| git remote add origin <your-repo-url> | |
| git push -u origin main | |
| ``` | |
| ## Skills to Port from Original Daemon | |
| The following skills are worth porting: | |
| 1. **composio-calendar.md** - Google Calendar integration | |
| 2. **composio-gmail.md** - Gmail integration | |
| 3. **composio-drive.md** - Google Drive integration | |
| 4. **composio-notion.md** - Notion integration (if you use Notion) | |
| 5. **morning-briefing.md** - Combined email + calendar summary | |
| 6. **content-writing-authority.md** - Writing style guide | |
| ## Customization | |
| 1. **Main branch**: Update `MAIN_BRANCH` in `hooks/subagent-pr.sh` to match your workflow | |
| 2. **Repos to clone**: Edit `hooks/session-start.sh` to clone your projects | |
| 3. **Skills**: Add service-specific integration guides in `skills/` | |
| 4. **Context**: Add your personal/work context in respective directories | |
| 5. **Language**: Set your preferred language in README.md | |
| ## Standards Compliance | |
| ✅ Uses `skills/` instead of `.claude/skills/` | |
| ✅ Uses `AGENTS.md` for workflow documentation | |
| ✅ Hooks in dedicated `hooks/` directory | |
| ✅ Clear separation: config in root, logic in subdirectories | |
| ✅ Standard Python tooling (uv, pyproject.toml) | |
| ✅ Markdown-first for all documentation | |
| ## Next Steps After Setup | |
| 1. Copy your API keys to `.env` | |
| 2. Run: `uv sync` to install dependencies | |
| 3. Start a Claude Code session | |
| 4. The SessionStart hook will prepare your environment | |
| 5. Start adding your context to markdown files | |
| 6. Work with Claude, commit via PRs | |
| 7. Your knowledge persists across sessions! | |
| --- | |
| **Remember**: GitHub is your memory. Markdown files are your thoughts. PRs are memory updates. Let the system work for you. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment