feat: .walnut package format + alive:share + alive:receive skills#19
Closed
patrickSupernormal wants to merge 22 commits intostackwalnuts:mainfrom
Closed
feat: .walnut package format + alive:share + alive:receive skills#19patrickSupernormal wants to merge 22 commits intostackwalnuts:mainfrom
patrickSupernormal wants to merge 22 commits intostackwalnuts:mainfrom
Conversation
Structured, persistent context management. 12 skills, 6 rules, 12 hooks, capsule architecture, squirrel runtime. Plain files on your machine. Every session compounds. github.com/alivecomputer
The squirrel wakes up aware. World key injected at first breath.
Capsule awareness detects deliverables mid-session. Repo reverse-lookup
maps any cwd to its walnut. The statusline shows where you are.
Session runtime:
- World key (.alive/key.md) injected via additionalContext on startup
- Capsule awareness prompt — auto-detects work with a future audience
- Tidy nudge when the world hasn't been cleaned in 7+ days
- Repo detection hook — dev.local_path → walnut context injection
- Squirrel instinct 8: verify past context via subagent, never guess
- Squirrel instinct 9: notice world key drift, flag stale connections
Index-driven architecture:
- Replaced manual ## Walnuts table with generated _index.yaml
- Tidy checks index freshness, not table drift
- World skill checks index staleness, offers regeneration
- Create skill no longer appends to a maintained table
Capsule system:
- New alive:capsule skill (create, share, graduate, status)
- Capsule-aware load menu (continue capsule / start new / load context)
- Shared capsule tracking in companion frontmatter
- Ungraduated capsule detection in tidy (v1 files still in _core/_capsules/)
- Version naming: {name}-draft-{nn}.md (self-documenting in walnut root)
Developer workflow:
- key-codebase.md template — dev: block with repo, local_path, deploy, database
- Create skill Step 2b — explicit codebase detection and field collection
- Multi-account native — different git/deploy/db identities per walnut
- Frontmatter-only parsing in repo-detect hook (safe, no body false positives)
Squirrel consolidation:
- Per-walnut _core/_squirrels/ killed — world-level .alive/_squirrels/ only
- saves: counter replaces signed: boolean
- Squirrel YAML template enriched (transcript, cwd, rules_loaded, tags)
Statusline:
- Active walnut name displayed when loaded
- Token cost dim + strikethrough (most users on OAuth — iykyk)
Cherry-picked from phase-0-1-foundation-and-rules branch.
Take 16, skip 5, fix 2.
Capsule companions no longer have their own task list. Tasks live in the walnut's _core/tasks.md under a capsule heading. Companion ## Tasks section replaced with a pointer. Prevents split source of truth where tasks exist in both places. Re-added deploy.sh (lost in force-push). Updated: templates/capsule/companion.md, rules/capsules.md Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The world index was generated but never injected — the squirrel had no boot-time walnut registry. Session hook now reads .alive/_index.yaml and injects it wrapped in <WORLD_INDEX> tags alongside the world key. This gives the squirrel immediate awareness of all walnuts, their phases, next actions, capsule counts, people, and links — without needing to scan the filesystem. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…sks-and-cleanup Capsule tasks, world injection and cleanup
- Format spec covers archive structure (tar.gz), three scope levels (full, capsule, snapshot), naming conventions, encryption via age, export stripping rules, import safety checks, and versioning policy - Manifest template defines all required/optional fields with types, descriptions, and BagIt-inspired SHA-256 integrity checksums Task: fn-1-89m.1 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Clarify encrypted flag semantics (reflects package encryption state)
- Full scope: note _working/ and _references/ as "if present"
- Add capsule version immutability guarantee (byte-for-byte export)
- Strengthen sensitivity/PII language to MUST surface + SHOULD confirm
- active_sessions stripping: remove key entirely, not just empty it
- Add sort recommendation for file inventory entries
- Fix template size placeholder to use {{size_bytes}}
- Add AppleDouble exclusion to full scope exclusions
Task: fn-1-89m.1
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Use explicit -f - in tar pipelines for GNU tar portability
- Template encrypted field as {{encrypted}} instead of hardcoded false
- Remove contradictory "always false inside archive" claim
- Mark .walnut.meta sidecar as OPTIONAL/MAY throughout
- Broaden encryption spec to allow recipient-based age (not just passphrase)
- Add walnut-name slug normalization note (lowercase kebab-case)
Task: fn-1-89m.1
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Make manifest.yaml valid YAML: use concrete example values for
non-string fields (boolean, integer) instead of {{placeholders}}
- Fix "Schema version" -> "Format version" in manifest header comment
- Fail closed when age not installed and encryption requested
- Add note about template substitution convention
Task: fn-1-89m.1
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- SKILL.md with 8-step flow: scope selection, capsule picker, sensitivity gate, scope confirmation, encryption prompt, package creation, output, and metadata update - Three scopes: full (entire _core/), capsule (selected capsules + key.md), snapshot (key + now + insights) - Sensitivity/PII gating follows confirm-before-external pattern - Optional age passphrase encryption with .walnut.meta sidecar - SHA-256 checksums via shasum (macOS) with sha256sum fallback (Linux) - active_sessions stripped from exported capsule companions - Cross-capsule broken path warnings - Large package (>25 MB) warnings - Capsule companion shared: metadata updated after export Task: fn-1-89m.2
- Fix double .walnut extension: use $OUTPUT_BASE pattern so tar commands write to $OUTPUT_BASE.walnut or $OUTPUT_BASE.walnut.age directly - Fix meta sidecar path: always $OUTPUT_BASE.walnut.meta (sits next to .walnut.age, not appended to the full encrypted path) - Add deterministic Python snippet for stripping active_sessions: from capsule companions in staging (no sed, no PyYAML dependency) - Group capsule picker by status: active capsules first, done capsules in separate section Task: fn-1-89m.2
- SKILL.md with full flow: encryption detection, path traversal protection, SHA-256 checksum validation, content preview, and scope-based routing - Three scope handlers: full (new walnut), capsule (existing walnut), snapshot (read-only) - Two entry points: direct /alive:receive invocation and inbox scan delegation - Security: staging extraction, path validation, format/plugin version checks - Handles log.md via bash to work with log guardian hook - Cleanup archives .walnut files from 03_Inputs/ (mv, not delete) Task: fn-1-89m.3
- Pre-extraction path validation via tar -tzf before extracting (prevents path traversal attacks during extraction, not just after) - Reject ALL symlinks in packages (safe in staging != safe at destination) - Reject special file types (device nodes, FIFOs, sockets) - Pipeline failure handling with PIPESTATUS checks for age | tar - Fixed mktemp template to use 8 X's (macOS BSD mktemp compatibility) - Size validation alongside checksum validation - Guard against empty manifest entries (regex parse failure detection) - Note that checksums detect corruption, not authenticity - Target path validation: all writes must resolve inside world root - Archive move collision handling with timestamp suffix - World root discovery and plugin version instructions in prerequisites Task: fn-1-89m.3
- Pre-extraction type validation via tar -tvzf (rejects symlinks and special file types BEFORE extraction, preventing symlink-then-write attacks) - PIPESTATUS checks on both age and tar in encrypted listing pipeline - mktemp for members file (prevents clobber/race on fixed /tmp path) - trap cleanup for staging and members file on early exit - Unencrypted extraction exit status check added - Manifest path validation: reject absolute, traversal, and out-of-staging paths in manifest entries before opening files - Streaming hash in 64KB chunks (prevents unbounded memory reads) - Per-file 500MB and total 2GB safety caps against decompression bombs - os.path.commonpath for world-root containment (more robust than string prefix) - Fixed misleading mv -n comment Task: fn-1-89m.3
- Replace tar -tvzf text parsing with Python tarfile module for portable, reliable member validation (handles PAX headers, bsdtar/gnutar differences) - Validate-then-extract in single tarfile open: check all members, then extract only safe_members (regular files + dirs, no symlinks/links/specials) - Encrypted path: decrypt to temp file via age -d -o, then tarfile (avoids double passphrase prompt from piped approach) - Capsule "Replace" now correctly removes old capsule before copy (rm -rf) - rsync --no-perms --no-owner --no-group to avoid foreign permission bits - Step 8 cleanup conditionally checks package is in 03_Inputs/ before archiving (matches prose requirement, prevents accidental Desktop file moves) - Normalize manifest paths (strip ./) for reliable unlisted-file comparison - Preserve full compound extensions in archive collision rename Task: fn-1-89m.3
- Fix lstrip('./') path traversal bypass: replace with proper while-loop
stripping that only removes leading './' sequences (not arbitrary chars)
- Add pre-extraction size caps in tarfile validation: MAX_MEMBERS (10k),
MAX_TOTAL_BYTES (2GB), MAX_PATH_LEN (512), checked before extractall
- Case-insensitive duplicate path detection (macOS HFS+/APFS safety)
- Step 8 inbox check uses containment (case prefix) instead of exact
directory equality (handles 03_Inputs/ subdirectories)
- Plugin version: warn and skip check if undeterminable (don't fabricate)
- All Python scripts use single-quoted -c strings (prevents shell mangling
of regex escapes in the manifest checksum script)
- Compiled regex for manifest parsing with fail-closed on unexpected format
- Display safety: sanitize manifest strings for terminal escape injection
- Agent state note: trap doesn't persist between tool calls, store staging
path in conversation state, explicit cleanup in every abort path
- Log.md handling clarified: bash for initial write, Edit for new unsigned
prepend entries (log guardian permits both patterns)
- rsync replaced with -rt --no-links --no-specials --no-devices
(defense in depth, no foreign permissions)
Task: fn-1-89m.3
- PAX/GNU metadata entries (XHDTYPE, XGLTYPE, longname, longlink) allowed but skipped during extraction instead of rejected - Stream-iterate tar members instead of loading all into memory (abort early when caps exceeded) - Check raw member name for '..' BEFORE normpath (which erases internal ..) - Control character rejection in archive paths (ASCII C0, DEL, C1 range) - Unicode-normalized + casefold duplicate detection (NFC normalization catches macOS APFS/HFS+ NFC vs NFD collisions) - Manifest reading via Python with control char sanitization (no raw cat) - All Python scripts consistently use single-quoted -c strings - Compound extension handling for archive collision rename (*.walnut.age, *.walnut.meta, *.walnut) - Manifest regex format constraints documented inline - Step 8 inbox check uses path prefix containment (handles subdirs) Task: fn-1-89m.3
- Remove \r from allowed display chars (terminal spoofing via carriage return) - Consistent display sanitization note for Step 1, 4, and 5 - Shell option-injection protection: add -- to all commands with untrusted paths (mkdir, mv, cat, rsync) - Skip tar entries that normalize to "." or empty (prevent staging dir modification) - Raw name length cap (16KB) before split to prevent DoS from huge PAX paths - Step 8: compute TIMESTAMP unconditionally (fixes unset var when only meta collides) - Step 8: pwd -P for symlink-safe containment check - Full scope copy uses rsync -rt --no-links --no-specials --no-devices - Session ID replacement uses lambda + sanitized source name (prevents regex backrefs) - UTF-8 with errors="replace" for untrusted file reads Task: fn-1-89m.3
- Add alive:share and alive:receive to CLAUDE.md skill table (12 → 14 skills) - Update inbox-check hook to detect .walnut/.walnut.age files and nudge with alive:receive - Add .walnut file delegation to capture skill's inbox scan mode Task: fn-1-89m.4
Add leading / to alive:receive and alive:capture references in nudge messages so they match the slash-command convention used everywhere else. Task: fn-1-89m.4
- Replace age with openssl enc for encryption (no terminal interaction needed) - Passphrase collected through session, passed via env var - Encrypted packages are single .walnut file (manifest.yaml cleartext + payload.enc) - No more .walnut.age or .walnut.meta sidecar files - Add recipient prompt for shared: metadata - Hardcode template paths (no Explore agent) - Strip macOS extended attributes from output - Update receive skill for new encrypted format - Update format spec and inbox-check hook Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…dir fix - Receive skill searches for source walnut by name before showing list - Walnut discovery uses no depth limit to find sub-walnuts - Nested walnut list shows sub-walnuts indented under parents - Capsule import offers create-new-walnut alongside import-into-existing - Archive enforcer allows cleanup in system temp directories - Archive enforcer skips paths with unexpanded shell variables Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
.walnutpackage format — a portable, optionally encrypted archive for sharing walnut context between worldsalive:shareskill — exports walnuts/capsules as .walnut packages with scope selection, sensitivity checks, and optional age encryptionalive:receiveskill — imports .walnut packages with path traversal protection, checksum validation, and per-file keep/drop routingFiles changed
templates/walnut-package/format-spec.mdtemplates/walnut-package/manifest.yamlskills/share/SKILL.mdskills/receive/SKILL.mdCLAUDE.mdhooks/scripts/alive-inbox-check.shskills/capture/SKILL.mdDesign
Full design research at
_core/_capsules/p2p-design/v0.1.md. This PR implements Phase 1 (package format) from the three-phase P2P architecture.Three scope levels: full (entire walnut), capsule (one or more capsules), snapshot (read-only status briefing). Optional passphrase encryption via
age. BagIt-inspired manifest with SHA-256 integrity checks.Test plan
🤖 Generated with Claude Code
Co-Authored-By: Claude Opus 4.6 (1M context) noreply@anthropic.com