🔧 chore(spawn): update .gitignore to track spawn templates correctly

- allow tracking of specific hidden directories and files under spawn templates
- ensure agents can build properly with required template files

✨ feat(branch): add comprehensive branch template verification tool

- implemented verify_branch.py to compare branch vs template files
- supports ignoring files based on .registry_ignore.json patterns
- outputs missing, additional, and matched files for branch validation
- included usage instructions and error handling for robust operation

♻️ refactor(prax): fix logger branch logs path to use Path.home()

- replaced hardcoded "/home/aipass" with portable Path.home()
- allows logging directory creation to adapt to user environment

✨ feat(spawn): add default template files and ignore configs for agent branches

- added .backup_ignore.json, .migrations.json, .registry_ignore.json for agent templates
- introduced .template_registry.json to track template files and directories
- created local context and metadata files for branch identity and session tracking
- included dashboard and flow local markdown templates for branch status and management
- added artifacts birth_certificate template for branch registration metadata

✨ feat(spawn): add mock agent branch templates and backups for testing

- created mock branch with backup ignore and registry ignore files for efficient backups
- added template registry and migration definitions matching main agent template
- included local prompt, passport, observations, and dashboard templates for mock branch
- provided flow local markdown and artifact registration files for mock branch use
- duplicated verify_branch.py tool for mock branch environment consistency

♻️ refactor(spawn): unify verify_branch.py tool in agent and mock branches

- standardized branch verification script in both template sets
- ensures consistent branch-template comparison and ignores handling
This commit is contained in:
AIOSAI
2026-03-06 03:06:13 -08:00
parent 3cb1d98ed8
commit 23448dc066
31 changed files with 1920 additions and 1 deletions
+16
View File
@@ -39,6 +39,22 @@ artifacts/
tools/
aipass_json/
# Spawn templates MUST be tracked (agents need these files to build from)
!src/aipass/spawn/templates/**/.trinity/
!src/aipass/spawn/templates/**/.trinity/**
!src/aipass/spawn/templates/**/.agent/
!src/aipass/spawn/templates/**/.agent/**
!src/aipass/spawn/templates/**/.aipass/
!src/aipass/spawn/templates/**/.aipass/**
!src/aipass/spawn/templates/**/.archive
!src/aipass/spawn/templates/**/.archive/**
!src/aipass/spawn/templates/**/artifacts/
!src/aipass/spawn/templates/**/artifacts/**
!src/aipass/spawn/templates/**/tools/
!src/aipass/spawn/templates/**/tools/**
!src/aipass/spawn/templates/**/DASHBOARD.local.json
!src/aipass/spawn/templates/**/flow.local.md
# Seedgo runtime artifacts (created by seedgo audit)
.seed/
.standards/
@@ -0,0 +1,168 @@
# DPLAN-047: Path.home() Purge — AIPass Portability Fix
**Status:** READY
**Created:** 2026-03-06
**Priority:** CRITICAL — blocks all Docker/container testing
**Parent:** MPLAN-001 (AIPass Public Repo Build)
**Triggered by:** Docker container testing revealed `Permission denied: '/home/aipass'` on `drone @seedgo audit aipass`
---
## Problem
Every module in AIPass uses `Path.home()` or hardcoded `/home/aipass` strings to resolve paths at module level (import time). This means:
- **0 of 10 modules** are portable
- **107 module-level bindings** crash on any machine that isn't ours
- A pip user running `from aipass.prax import logger` gets `Permission denied` immediately
- Docker container (the acceptance test) fails on basic commands
### Root Cause
Code was transferred from Dev-Pass (where `/home/aipass` is the fixed root) to AIPass (pip package, root is wherever the user cloned it). The import rewire (FPLAN-0409) fixed `from` statements but didn't touch path resolution.
### The Fix Pattern
```python
# WRONG — Dev-Pass pattern (breaks everywhere else)
SYSTEM_LOGS_DIR = Path.home() / "system_logs"
BRANCH_REGISTRY = Path.home() / "BRANCH_REGISTRY.json"
API_ROOT = Path.home() / "aipass_core" / "api"
# RIGHT — Package-relative (works everywhere)
# Option A: Walk up from __file__ to find repo root
REPO_ROOT = Path(__file__).resolve().parents[N] # N = depth to repo root
# Option B: Walk-up finder (already used by drone/seedgo)
def _find_repo_root() -> Path:
current = Path(__file__).resolve().parent
for parent in [current] + list(current.parents):
if (parent / "AIPASS_REGISTRY.json").exists():
return parent
return Path.cwd()
```
---
## Scope — Module Debt Count
| Module | Path.home() | Hardcoded /home/aipass | Module-Level | Severity |
|--------|-------------|----------------------|--------------|----------|
| api | 40 | 20 | 33 | CRITICAL |
| ai_mail | 35 | 20 | 22 | CRITICAL |
| prax | 16 | 23 | 9 | CRITICAL |
| flow | 15 | 26 | 6 | HIGH |
| trigger | 8 | 14 | 8 | MEDIUM |
| seedgo | 10 | 66* | 0 | DONE (seed purged) |
| drone | 2 | 0 | 1 | LOW (fallback only) |
| cli | 2 | 11 | 2 | LOW |
| spawn | 2 | 0 | 2 | LOW |
| devpulse | 1 | 0 | 1 | LOW |
*seedgo 66 count is 59 documentation strings + 7 code. Seed already fixed all runtime breakers.
---
## Phase Plan
### Phase 0: Immediate Unblock (DEV_CENTRAL — done)
- [x] AIPASS_REGISTRY.json DEVPULSE absolute path fixed
- [x] README.md fake import paths fixed
- [x] pyproject.toml missing watchdog dependency added
- [x] Seedgo Path.home() purge dispatched to @seed (12 files, AST-verified clean)
- [x] Prax setup.py:125 hardcoded `Path("/home/aipass")` fixed
- [ ] Commit + push all pending changes
### Phase 1: Prax Logger Unblock (dispatch to @prax)
**Goal:** `from aipass.prax import logger` works in container
**Files:** 8 module-level bindings in prax
**Key targets:**
- config/load.py:51 — SYSTEM_LOGS_DIR = Path.home()
- config/load.py:55 — mkdir at import time
- setup.py:125 — branch_logs_dir (FIXED)
- introspection.py:103 — parts.index('aipass') username assumption
- registry/reader.py:34 — BRANCH_REGISTRY_PATH
- dashboard/agent_status_writer.py:45 — BRANCH_REGISTRY
- monitoring/telegram_command_bot.py:68 — AIPASS_HOME cascade
- monitoring/telegram_relay.py:60 — PRAX_MONITOR_CONFIG
- log_watchdog.py:44 — SYSTEM_LOGS_DIR duplicate
**Fix pattern:** Lazy initialization. Don't mkdir at import time. Use repo-relative paths.
### Phase 2: Core Module Purge (parallel dispatch)
**Goal:** drone, cli, spawn, devpulse portable
**These are small** — 1-2 fixes each. Can dispatch in parallel.
- drone config.py:41 — fallback Path.home() (already has walk-up, just remove fallback)
- cli json_handler.py:27 — CLI_ROOT
- spawn verify_branch.py — AIPASS_ROOT
- devpulse verify_branch.py — AIPASS_ROOT
### Phase 3: Heavy Modules (parallel dispatch, larger scope)
**Goal:** flow, trigger, ai_mail, api portable
**These are big** — 6-33 module-level bindings each.
Strategy: Many of these paths reference Dev-Pass infrastructure that doesn't exist in AIPass (MEMORY_BANK, AI_CENTRAL, BRANCH_REGISTRY.json, telegram bots, daemon). Two options per reference:
1. **Rewire to repo-relative** — if the feature exists in AIPass
2. **Guard with try/except or conditional** — if it's a Dev-Pass-only feature
3. **Remove entirely** — if the code shouldn't be in the public repo at all
**Decision needed from Patrick:** Which modules should ship functional vs stub in v1.0?
- api telegram handlers — probably Dev-Pass only (not for pip users)
- ai_mail daemon/dispatch — probably Dev-Pass only
- flow AI_CENTRAL aggregation — probably Dev-Pass only
- trigger event handlers — probably Dev-Pass only
### Phase 4: Docker Verification
**Goal:** Full test suite passes in container
- `pip install -e .` clean
- `drone --help` works
- `drone systems` works
- `drone @seedgo audit aipass` works
- `drone @seedgo verify` works
- `drone @seedgo list` works
- Python imports work: `from aipass.drone import ...`, `from aipass.prax import logger`
---
## Key Decision: What Ships in v1.0?
The massive path debt in api (40), ai_mail (35), flow (15) is because these modules contain Dev-Pass infrastructure code (telegram bots, daemon dispatch, AI_CENTRAL aggregation) that pip users will never use.
**Option A: Fix everything** — rewire all 131 Path.home() calls. Massive effort, most code is dead weight for pip users.
**Option B: Strip Dev-Pass code from public modules** — ship only the pip-relevant parts. Faster, cleaner, but requires deciding what's public vs private per module.
**Option C: Guard at module boundary** — keep all code but wrap Dev-Pass features in `try/import` guards so they don't crash when infrastructure is missing. Middle ground.
**Recommendation:** Option B for v1.0. Ship lean. The telegram bridge, daemon dispatch, and AI_CENTRAL aggregation are Dev-Pass features. Public users need: drone routing, seedgo auditing, prax logging (basic), flow planning (basic), cli formatting.
---
## Container Test Checklist (Acceptance Criteria)
```bash
# In Docker container (clean clone, pip install -e .)
source .venv/bin/activate
pip install -e .
# Core commands
drone --help # Must work
drone systems # Must show 10 branches
drone @seedgo verify # Must pass 5/5
drone @seedgo list # Must show packs
drone @seedgo audit aipass # Must run without Permission denied
# Python imports
python3 -c "from aipass.drone.apps.modules.registry import load_registry; print(load_registry())"
python3 -c "from aipass.prax import logger; logger.info('test')"
python3 -c "from aipass.cli import console, header; header('test')"
```
---
## Notes
- Shebangs (`#!/home/aipass/.venv/bin/python3`) are cosmetic — don't affect pip imports
- Display strings in seedgo standards checkers are documentation, not runtime
- The walk-up `_find_registry()` pattern is proven — drone and seedgo already use it
- Dev-Pass and AIPass can coexist on same machine (different venvs, different registries)
@@ -122,7 +122,7 @@ def setup_individual_logger(module_name: str) -> logging.Logger:
if branch:
# Create branch logs directory if it doesn't exist
# Branch format is now "aipass_core/module" or "project_name"
branch_logs_dir = Path("/home/aipass") / branch / "logs"
branch_logs_dir = Path.home() / branch / "logs"
branch_logs_dir.mkdir(parents=True, exist_ok=True)
# Create branch-local log file
@@ -0,0 +1,37 @@
{
"metadata": {
"version": "1.0.0",
"description": "Files and patterns to exclude when creating branch backups"
},
"ignore_directories": [
".backup",
".venv",
"venv",
"node_modules",
"__pycache__",
".git",
".cache",
".pytest_cache",
".mypy_cache",
"dist",
"build",
"*.egg-info",
"ai_mail.local",
"logs",
".aipass",
".archive",
".claude",
"htmlcov"
],
"ignore_patterns": [
"*.pyc",
"*.pyo",
".DS_Store",
"*.log",
"*.tmp",
"*.swp",
"*~",
"*.env",
"BRANCH_REGISTRY.json"
]
}
@@ -0,0 +1,49 @@
{
"metadata": {
"version": "1.0.0",
"description": "Template structural migrations for branch updates",
"last_updated": "2025-11-07",
"applies_to_versions": ["all"]
},
"migrations": [
{
"id": "m001",
"description": "Example: Migrate flat metadata to document_metadata structure",
"version_introduced": "1.0.0",
"applies_to_files": ["*.id.json"],
"operations": [
{
"type": "key_rename",
"from": "metadata",
"to": "document_metadata"
},
{
"type": "move_to_nested",
"source_keys": ["branch_name", "path", "profile"],
"target_parent": "branch_info"
},
{
"type": "add_missing_keys",
"parent": "document_metadata",
"keys": {
"document_type": "branch_identity",
"schema_version": "1.0.0"
}
}
]
}
],
"options": {
"skip_if_target_exists": true,
"preserve_unknown_keys": true,
"recursive_application": false
},
"notes": {
"usage": "This file defines structural transformation rules applied during branch updates",
"pattern_matching": "applies_to_files uses glob patterns (*.json, *.id.json, etc.)",
"operation_order": "Operations execute in order listed within each migration",
"skip_behavior": "Operations skip if already compliant (target exists = success)",
"supported_operations": ["key_rename", "move_to_nested", "add_missing_keys"],
"future_operations": ["split_key", "combine_keys", "delete_key", "transform_value"]
}
}
@@ -0,0 +1,43 @@
{
"metadata": {
"version": "1.1.0",
"description": "Files and patterns to exclude when updating branches from template",
"last_updated": "2025-11-09"
},
"ignore_files": [
".template_registry.json",
".registry_ignore.json"
],
"ignore_patterns": [
"__pycache__",
"*.pyc",
"#@comments.txt",
".backup_*"
],
"notes": {
"how_it_works": "Two types of exclusions during branch updates:",
"ignore_files": {
"description": "Exact filename matches (no wildcards)",
"purpose": "Template-internal management files that branches don't need",
"examples": [
".template_registry.json (template's file tracking list)",
".registry_ignore.json (this config file)"
]
},
"ignore_patterns": {
"description": "Glob patterns - matches filenames AND directory names",
"purpose": "Exclude generated files, caches, and user content markers",
"examples": [
"__pycache__ (Python cache directories)",
"*.pyc (Python compiled bytecode files)",
"#@comments.txt (user comment files)",
".backup_* (timestamped backup files like .backup_20251109, NOT .backup directory)"
],
"how_matching_works": [
"Step 1: Check if filename matches pattern (e.g., file.pyc matches *.pyc)",
"Step 2: Check if any parent directory matches (e.g., files inside __pycache__/ dir)"
]
},
"what_gets_ignored": "These files never copy to branches during updates - they stay template-only"
}
}
@@ -0,0 +1,301 @@
{
"metadata": {
"version": "1.0.0",
"last_updated": "2026-02-20",
"description": "Template file tracking registry for ID-based updates"
},
"files": {
"f001": {
"current_name": "BRANCH.ID.json",
"path": "BRANCH.ID.json",
"content_hash": "e9bc2347d373",
"has_branch_placeholder": false
},
"f003": {
"current_name": "dev.local.md",
"path": "dev.local.md",
"content_hash": "6c1c5e099790",
"has_branch_placeholder": false
},
"f035": {
"current_name": ".gitkeep",
"path": "ai_mail.local/.archive/.gitkeep",
"content_hash": "e3b0c44298fc",
"has_branch_placeholder": false
},
"f008": {
"current_name": "DASHBOARD.local.json",
"path": "DASHBOARD.local.json",
"content_hash": "3f0528b4c5d5",
"has_branch_placeholder": false
},
"f007": {
"current_name": ".migrations.json",
"path": ".migrations.json",
"content_hash": "4ca241607dc3",
"has_branch_placeholder": false
},
"f010": {
"current_name": "OBSERVATIONS.json",
"path": "OBSERVATIONS.json",
"content_hash": "58ea8609fbe0",
"has_branch_placeholder": false
},
"f011": {
"current_name": "requirements.txt",
"path": "requirements.txt",
"content_hash": "66dfffc70d53",
"has_branch_placeholder": false
},
"f021": {
"current_name": "README.md",
"path": "README.md",
"content_hash": "4e946f67a130",
"has_branch_placeholder": false
},
"f012": {
"current_name": "LOCAL.json",
"path": "LOCAL.json",
"content_hash": "459dbe18d40a",
"has_branch_placeholder": false
},
"f006": {
"current_name": "pytest.ini",
"path": "pytest.ini",
"content_hash": "7b39ba7bca40",
"has_branch_placeholder": false
},
"f022": {
"current_name": "_template.md",
"path": "docs/_template.md",
"content_hash": "79ce97b0e613",
"has_branch_placeholder": false
},
"f016": {
"current_name": "__init__.py",
"path": "tests/__init__.py",
"content_hash": "1fcd8126d174",
"has_branch_placeholder": false
},
"f019": {
"current_name": "conftest.py",
"path": "tests/conftest.py",
"content_hash": "2887db109a6b",
"has_branch_placeholder": false
},
"f004": {
"current_name": "BRANCH.py",
"path": "apps/BRANCH.py",
"content_hash": "44f22cc95232",
"has_branch_placeholder": false
},
"f009": {
"current_name": "__init__.py",
"path": "apps/__init__.py",
"content_hash": "5c38204be5fc",
"has_branch_placeholder": false
},
"f013": {
"current_name": "#@comments.txt.removed_from_template",
"path": ".archive/#@comments.txt.removed_from_template",
"content_hash": "651126c1e7a9",
"has_branch_placeholder": false
},
"f028": {
"current_name": "deleted.json.old_template_format",
"path": ".archive/deleted.json.old_template_format",
"content_hash": "48a3a33dd73a",
"has_branch_placeholder": false
},
"f002": {
"current_name": "branch_system_prompt.md",
"path": ".aipass/branch_system_prompt.md",
"content_hash": "897c7beb66f5",
"has_branch_placeholder": false
},
"f026": {
"current_name": "inbox.json",
"path": "ai_mail.local/inbox.json",
"content_hash": "c9702fe2cc21",
"has_branch_placeholder": false
},
"f027": {
"current_name": "sent.json",
"path": "ai_mail.local/sent.json",
"content_hash": "240132e5a567",
"has_branch_placeholder": false
},
"f014": {
"current_name": "__init__.py",
"path": "apps/handlers/__init__.py",
"content_hash": "657d98ad4b98",
"has_branch_placeholder": false
},
"f015": {
"current_name": "__init__.py",
"path": "apps/json_templates/__init__.py",
"content_hash": "330b189c08c7",
"has_branch_placeholder": false
},
"f020": {
"current_name": "__init__.py",
"path": "apps/plugins/__init__.py",
"content_hash": "39158d26a19c",
"has_branch_placeholder": false
},
"f023": {
"current_name": "__init__.py",
"path": "apps/modules/__init__.py",
"content_hash": "bc25a8b75e81",
"has_branch_placeholder": false
},
"f024": {
"current_name": "__init__.py",
"path": "apps/extensions/__init__.py",
"content_hash": "6742ceb64ec1",
"has_branch_placeholder": false
},
"f032": {
"current_name": "data.json",
"path": "apps/json_templates/default/data.json",
"content_hash": "0531a02be998",
"has_branch_placeholder": false
},
"f033": {
"current_name": "log.json",
"path": "apps/json_templates/default/log.json",
"content_hash": "37517e5f3dc6",
"has_branch_placeholder": false
},
"f034": {
"current_name": "config.json",
"path": "apps/json_templates/default/config.json",
"content_hash": "3759a05e171d",
"has_branch_placeholder": false
},
"f005": {
"current_name": "json_handler.py",
"path": "apps/handlers/json/json_handler.py",
"content_hash": "3449629aff23",
"has_branch_placeholder": false
},
"f017": {
"current_name": "__init__.py",
"path": "apps/handlers/json/__init__.py",
"content_hash": "ad3629e381ca",
"has_branch_placeholder": false
}
},
"directories": {
"d001": {
"current_name": "tools",
"path": "tools",
"has_branch_placeholder": false
},
"d002": {
"current_name": "docs",
"path": "docs",
"has_branch_placeholder": false
},
"d003": {
"current_name": "tests",
"path": "tests",
"has_branch_placeholder": false
},
"d004": {
"current_name": "apps",
"path": "apps",
"has_branch_placeholder": false
},
"d005": {
"current_name": ".archive",
"path": ".archive",
"has_branch_placeholder": false
},
"d006": {
"current_name": "logs",
"path": "logs",
"has_branch_placeholder": false
},
"d009": {
"current_name": ".backup",
"path": ".backup",
"has_branch_placeholder": false
},
"d008": {
"current_name": "{{BRANCH}}_json",
"path": "{{BRANCH}}_json",
"has_branch_placeholder": true
},
"d010": {
"current_name": "artifacts",
"path": "artifacts",
"has_branch_placeholder": false
},
"d012": {
"current_name": ".aipass",
"path": ".aipass",
"has_branch_placeholder": false
},
"d011": {
"current_name": "ai_mail.local",
"path": "ai_mail.local",
"has_branch_placeholder": false
},
"d007": {
"current_name": "dropbox",
"path": "dropbox",
"has_branch_placeholder": false
},
"d013": {
"current_name": "handlers",
"path": "apps/handlers",
"has_branch_placeholder": false
},
"d014": {
"current_name": "json_templates",
"path": "apps/json_templates",
"has_branch_placeholder": false
},
"d015": {
"current_name": "plugins",
"path": "apps/plugins",
"has_branch_placeholder": false
},
"d016": {
"current_name": "modules",
"path": "apps/modules",
"has_branch_placeholder": false
},
"d017": {
"current_name": "extensions",
"path": "apps/extensions",
"has_branch_placeholder": false
},
"d018": {
"current_name": "sent",
"path": "ai_mail.local/sent",
"has_branch_placeholder": false
},
"d019": {
"current_name": "deleted",
"path": "ai_mail.local/deleted",
"has_branch_placeholder": false
},
"d020": {
"current_name": ".archive",
"path": "ai_mail.local/.archive",
"has_branch_placeholder": false
},
"d027": {
"current_name": "json",
"path": "apps/handlers/json",
"has_branch_placeholder": false
},
"d024": {
"current_name": "default",
"path": "apps/json_templates/default",
"has_branch_placeholder": false
}
}
}
@@ -0,0 +1,14 @@
# {{BRANCHNAME}} Branch-Local Context
<!-- Source: {{CWD}}/.aipass/branch_system_prompt.md -->
> Auto-created by aipass init. Customize for your branch.
## Status: NEEDS CONFIGURATION
This file is injected into every AI conversation when working from this branch directory. Configure it with:
- Who this branch is (role, purpose)
- Key commands and workflows
- Architecture overview
- Critical files and operational rules
- Integration points with other branches
@@ -0,0 +1,34 @@
{
"document_metadata": {
"document_type": "session_history",
"document_name": "{{BRANCHNAME}}.LOCAL",
"version": "1.0.0",
"schema_version": "1.0.0",
"created": "{{DATE}}",
"last_updated": "{{DATE}}",
"managed_by": "{{BRANCHNAME}}",
"tags": ["session_tracking", "work_log", "{{BRANCHNAME}}"],
"limits": {
"max_lines": 600,
"note": "Auto-rollover when max_lines exceeded"
},
"status": {
"health": "healthy",
"current_lines": 0,
"last_health_check": "{{DATE}}"
}
},
"active_tasks": {
"today_focus": "{{DATE}}",
"recently_completed": []
},
"key_learnings": {},
"sessions": [
{
"session_number": 1,
"date": "{{DATE}}",
"summary": "Branch initialized - {{BRANCHNAME}} created by aipass init",
"status": "completed"
}
]
}
@@ -0,0 +1,37 @@
{
"document_metadata": {
"document_type": "collaboration_patterns",
"document_name": "{{BRANCHNAME}}.OBSERVATIONS",
"version": "1.0.0",
"schema_version": "1.0.0",
"created": "{{DATE}}",
"last_updated": "{{DATE}}",
"managed_by": "{{BRANCHNAME}}",
"tags": ["collaboration", "patterns", "{{BRANCHNAME}}"],
"limits": {
"max_lines": 600,
"note": "Auto-rollover when max_lines exceeded"
},
"status": {
"health": "healthy",
"current_lines": 0,
"last_health_check": "{{DATE}}"
}
},
"guidelines": {
"purpose": "Capture collaboration patterns and experiential insights over time",
"chronological_order": "Newest entries at TOP, oldest at BOTTOM - NEVER reorder"
},
"observations": [
{
"date": "{{DATE}}",
"session": 1,
"entries": [
{
"title": "First Contact",
"detail": "Branch initialized. Ready to begin capturing collaboration patterns."
}
]
}
]
}
@@ -0,0 +1,36 @@
{
"document_metadata": {
"document_type": "branch_identity",
"document_name": "{{BRANCHNAME}}.PASSPORT",
"version": "1.0.0",
"schema_version": "1.0.0",
"created": "{{DATE}}",
"last_updated": "{{DATE}}",
"managed_by": "{{BRANCHNAME}}",
"tags": ["identity", "passport", "branch_profile"]
},
"branch_info": {
"branch_name": "{{BRANCHNAME}}",
"alias": "",
"path": "{{CWD}}",
"module": "{{MODULE}}",
"created": "{{DATE}}"
},
"identity": {
"role": "{{ROLE}}",
"purpose": "",
"what_i_do": [],
"what_i_dont_do": []
},
"principles": [
"Code is truth - fail honestly",
"Memory persists - context survives",
"Simple solutions over complex architecture"
],
"citizenship": {
"registered": true,
"registry_path": ".aipass/registry.json",
"communications": true,
"memory": true
}
}
@@ -0,0 +1,62 @@
{
"_warning": "AUTO-GENERATED FILE - DO NOT MANUALLY EDIT. This file is 100% automated and will be overwritten. Services update their own sections.",
"branch": "{{BRANCHNAME}}",
"last_updated": "{{DATE}}",
"quick_status": {
"new_mail": 0,
"opened_mail": 0,
"active_plans": 0,
"commons_mentions": 0,
"action_required": false,
"summary": ""
},
"sections": {
"ai_mail": {
"managed_by": "ai_mail",
"new": 0,
"opened": 0,
"total": 0,
"oldest_unread_age": null,
"last_dispatch_received": null,
"last_updated": "{{DATE}}"
},
"flow": {
"managed_by": "flow",
"active_plans": 0,
"recently_closed": [],
"last_updated": "{{DATE}}"
},
"memory_bank": {
"managed_by": "memory_bank",
"vectors_stored": 0,
"notes": {},
"last_updated": "{{DATE}}"
},
"devpulse": {
"managed_by": "devpulse",
"summary": {
"issues": 0,
"todos": 0
},
"dplan_counts": {},
"recent_activity": "",
"last_updated": "{{DATE}}"
},
"commons_activity": {
"managed_by": "the_commons",
"new_posts_since_last_visit": 0,
"new_comments_since_last_visit": 0,
"mentions": 0,
"trending": "None",
"last_checked": null,
"last_updated": "{{DATE}}"
},
"agent_status": {
"managed_by": "prax",
"active_agents": [],
"agent_count": 0,
"stale_agents": [],
"last_updated": "{{DATE}}"
}
}
}
@@ -0,0 +1,15 @@
{
"id": "{{CITIZEN_NUMBER}}",
"name": "{{BRANCHNAME}} Birth Certificate",
"type": "birth_certificate",
"creator": "SYSTEM",
"owner": "{{BRANCHNAME}}",
"rarity": "unique",
"description": "Official birth certificate for {{BRANCHNAME}}. Citizen #{{CITIZEN_NUMBER}}, registered using '{{PROFILE}}' template. Purpose: {{PURPOSE_BRIEF}}",
"metadata": {
"citizen_number": "{{CITIZEN_NUMBER}}",
"template": "{{PROFILE}}",
"purpose": "{{PURPOSE_BRIEF}}"
},
"created_at": "{{DATE}}"
}
@@ -0,0 +1,15 @@
# flow.local.md - {{BRANCHNAME}}
```
Branch: {{CWD}}
Created: {{DATE}}
```
## Issues
-
---
## Todos
-
@@ -0,0 +1,159 @@
#!/home/aipass/.venv/bin/python3
# -*- coding: utf-8 -*-
# ===================AIPASS====================
# META DATA HEADER
# Name: verify_branch.py - Branch Template Verification
# Date: 2025-11-08
# Version: 1.0.0
# Category: cortex/modules
#
# CHANGELOG (Max 5 entries):
# - v1.0.0 (2025-11-08): Initial implementation - Compare template vs branch
#
# CODE STANDARDS:
# - Error handling: Use error handler system (apps/handlers/error/)
# =============================================
"""
Branch Template Verification Tool
Compares template directory with created branch to identify:
- Files in template but missing in branch
- Files in branch but not in template
- Renamed files
"""
import sys
import json
from pathlib import Path
from typing import Set, List, Tuple
from fnmatch import fnmatch
# INFRASTRUCTURE IMPORT PATTERN
AIPASS_ROOT = Path.home() / "aipass_core"
sys.path.insert(0, str(AIPASS_ROOT))
# Get template directory
TEMPLATE_DIR = AIPASS_ROOT / "cortex" / "templates" / "branch_template"
def load_ignore_patterns() -> Tuple[List[str], List[str]]:
"""Load ignore patterns from .registry_ignore.json"""
ignore_file = TEMPLATE_DIR / ".registry_ignore.json"
if not ignore_file.exists():
return [], []
try:
with open(ignore_file, 'r', encoding='utf-8') as f:
data = json.load(f)
ignore_files = data.get("ignore_files", [])
ignore_patterns = data.get("ignore_patterns", [])
return ignore_files, ignore_patterns
except Exception as e:
print(f"Warning: Could not load .registry_ignore.json: {e}")
return [], []
def should_exclude(path: Path, base_dir: Path, ignore_files: List[str], ignore_patterns: List[str]) -> bool:
"""Check if path should be excluded based on ignore patterns"""
rel_path = path.relative_to(base_dir)
filename = path.name
path_str = str(rel_path)
# Check exact filename matches
if filename in ignore_files:
return True
# Check glob patterns
for pattern in ignore_patterns:
if fnmatch(filename, pattern):
return True
# Check if any parent directory matches
for part in rel_path.parts:
if fnmatch(part, pattern):
return True
return False
def get_file_set(directory: Path, ignore_files: List[str], ignore_patterns: List[str]) -> Set[str]:
"""Get set of all file paths in directory (relative)"""
files = set()
for item in directory.rglob("*"):
if item.is_file() and not should_exclude(item, directory, ignore_files, ignore_patterns):
rel_path = str(item.relative_to(directory))
files.add(rel_path)
return files
def verify_branch(branch_dir: Path) -> Tuple[List[str], List[str], List[str]]:
"""
Compare template with branch
Returns:
Tuple of (in_template_only, in_branch_only, in_both)
"""
# Load ignore patterns from .registry_ignore.json
ignore_files, ignore_patterns = load_ignore_patterns()
template_files = get_file_set(TEMPLATE_DIR, ignore_files, ignore_patterns)
branch_files = get_file_set(branch_dir, ignore_files, ignore_patterns)
in_template_only = sorted(template_files - branch_files)
in_branch_only = sorted(branch_files - template_files)
in_both = sorted(template_files & branch_files)
return in_template_only, in_branch_only, in_both
def main():
if len(sys.argv) < 2:
print("Usage: python3 verify_branch.py <branch_directory>")
print("Example: python3 verify_branch.py test_branch002")
sys.exit(1)
branch_path = Path(sys.argv[1])
if not branch_path.is_absolute():
# Assume it's relative to cortex directory
branch_path = Path.cwd() / branch_path
if not branch_path.exists():
print(f"❌ ERROR: Branch directory not found: {branch_path}")
sys.exit(1)
print(f"\n=== Branch Verification ===")
print(f"Template: {TEMPLATE_DIR}")
print(f"Branch: {branch_path}")
print()
in_template_only, in_branch_only, in_both = verify_branch(branch_path)
print(f"Files in both: {len(in_both)}")
print(f"Files in template only: {len(in_template_only)}")
print(f"Files in branch only: {len(in_branch_only)}")
print()
if in_template_only:
print("❌ Missing from branch (expected from template):")
for file in in_template_only:
print(f" - {file}")
print()
if in_branch_only:
print("✅ Additional files in branch (renamed or new):")
for file in in_branch_only:
print(f" + {file}")
print()
if not in_template_only and not in_branch_only:
print("✅ Branch matches template perfectly")
print("="*70)
if __name__ == "__main__":
main()
@@ -0,0 +1,133 @@
{
"metadata": {
"version": "1.0.0",
"description": "Files and patterns to exclude when creating branch backups",
"last_updated": "2025-11-09"
},
"ignore_directories": [
".backup",
"backups",
".venv",
"venv",
"node_modules",
"__pycache__",
".git",
".cache",
".pytest_cache",
".mypy_cache",
"dist",
"build",
"*.egg-info",
"aipass_dev",
"aipass_core",
"aipass_business",
"aipass_help",
"input_x",
"Link to mnt",
"mcp_servers",
"speakeasy",
"sandbox",
"ai_mail.local",
"logs",
"pruned_files",
"crash-logs",
".aipass",
".archive",
".cargo",
".codex",
".config",
".dbus",
".dotnet",
".gemini",
".gnome",
".gnupg",
".idlerc",
".java",
".local",
".mozilla",
".npm",
".npm-global",
".nvm",
".pki",
".pylint.d",
".pyenv",
".serena",
".ssh",
".thunderbird",
".var",
".vscode-server",
".wget-hsts",
".claude-code-docs",
".claude",
"backup_system",
"Desktop",
"Documents",
"Downloads",
"dropbox",
"Music",
"Pictures",
"Public",
"snap",
"system_logs",
"Templates",
"Videos"
],
"ignore_patterns": [
"*.pyc",
"*.pyo",
"*.pyd",
".DS_Store",
"Thumbs.db",
"*.log",
"*.tmp",
"*.swp",
"*.swo",
"*~",
"*.env",
"*_json",
"dev.local.md",
"notepad.md",
"pytest.ini",
".bash_history",
".bash_logout",
".bashrc",
".claude.json",
".claude.json.backup",
".lesshst",
".npmrc",
".profile",
".python_history",
".sudo_as_admin_successful",
".gitattributes",
"BRANCH_REGISTRY.json",
".branch_meta.json*",
"migrations.json*",
"sandbox.img"
],
"notes": {
"how_it_works": "Two types of exclusions during backup creation:",
"ignore_directories": {
"description": "Directory names to skip entirely (including all contents)",
"purpose": "Exclude large dependency dirs, caches, and backup dirs themselves",
"examples": [
".venv, venv (Python virtual environments - large, regeneratable)",
"node_modules (NPM dependencies - huge, regeneratable)",
"__pycache__, .cache (Python/system caches - regeneratable)",
".git (Git repository - already versioned)",
".backup, backups (backup directories - prevent recursion)"
]
},
"ignore_patterns": {
"description": "Glob patterns for files to skip",
"purpose": "Exclude temporary files, compiled bytecode, OS cruft",
"examples": [
"*.pyc, *.pyo (Python compiled bytecode - regeneratable)",
"*.log (Log files - can be large, temporary)",
"*.tmp, *.swp (Temporary/swap files)",
".DS_Store, Thumbs.db (OS metadata files)"
]
},
"customization": "Edit this file in the template to add more patterns. Changes take effect on next branch update.",
"performance": "Ignoring large directories dramatically speeds up backups (seconds vs minutes for branches with node_modules or .venv)"
}
}
@@ -0,0 +1,49 @@
{
"metadata": {
"version": "1.0.0",
"description": "Template structural migrations for branch updates",
"last_updated": "2025-11-07",
"applies_to_versions": ["all"]
},
"migrations": [
{
"id": "m001",
"description": "Example: Migrate flat metadata to document_metadata structure",
"version_introduced": "1.0.0",
"applies_to_files": ["*.id.json"],
"operations": [
{
"type": "key_rename",
"from": "metadata",
"to": "document_metadata"
},
{
"type": "move_to_nested",
"source_keys": ["branch_name", "path", "profile"],
"target_parent": "branch_info"
},
{
"type": "add_missing_keys",
"parent": "document_metadata",
"keys": {
"document_type": "branch_identity",
"schema_version": "1.0.0"
}
}
]
}
],
"options": {
"skip_if_target_exists": true,
"preserve_unknown_keys": true,
"recursive_application": false
},
"notes": {
"usage": "This file defines structural transformation rules applied during branch updates",
"pattern_matching": "applies_to_files uses glob patterns (*.json, *.id.json, etc.)",
"operation_order": "Operations execute in order listed within each migration",
"skip_behavior": "Operations skip if already compliant (target exists = success)",
"supported_operations": ["key_rename", "move_to_nested", "add_missing_keys"],
"future_operations": ["split_key", "combine_keys", "delete_key", "transform_value"]
}
}
@@ -0,0 +1,43 @@
{
"metadata": {
"version": "1.1.0",
"description": "Files and patterns to exclude when updating branches from template",
"last_updated": "2025-11-09"
},
"ignore_files": [
".template_registry.json",
".registry_ignore.json"
],
"ignore_patterns": [
"__pycache__",
"*.pyc",
"#@comments.txt",
".backup_*"
],
"notes": {
"how_it_works": "Two types of exclusions during branch updates:",
"ignore_files": {
"description": "Exact filename matches (no wildcards)",
"purpose": "Template-internal management files that branches don't need",
"examples": [
".template_registry.json (template's file tracking list)",
".registry_ignore.json (this config file)"
]
},
"ignore_patterns": {
"description": "Glob patterns - matches filenames AND directory names",
"purpose": "Exclude generated files, caches, and user content markers",
"examples": [
"__pycache__ (Python cache directories)",
"*.pyc (Python compiled bytecode files)",
"#@comments.txt (user comment files)",
".backup_* (timestamped backup files like .backup_20251109, NOT .backup directory)"
],
"how_matching_works": [
"Step 1: Check if filename matches pattern (e.g., file.pyc matches *.pyc)",
"Step 2: Check if any parent directory matches (e.g., files inside __pycache__/ dir)"
]
},
"what_gets_ignored": "These files never copy to branches during updates - they stay template-only"
}
}
@@ -0,0 +1,301 @@
{
"metadata": {
"version": "1.0.0",
"last_updated": "2026-02-20",
"description": "Template file tracking registry for ID-based updates"
},
"files": {
"f001": {
"current_name": "BRANCH.ID.json",
"path": "BRANCH.ID.json",
"content_hash": "e9bc2347d373",
"has_branch_placeholder": false
},
"f003": {
"current_name": "dev.local.md",
"path": "dev.local.md",
"content_hash": "6c1c5e099790",
"has_branch_placeholder": false
},
"f035": {
"current_name": ".gitkeep",
"path": "ai_mail.local/.archive/.gitkeep",
"content_hash": "e3b0c44298fc",
"has_branch_placeholder": false
},
"f008": {
"current_name": "DASHBOARD.local.json",
"path": "DASHBOARD.local.json",
"content_hash": "3f0528b4c5d5",
"has_branch_placeholder": false
},
"f007": {
"current_name": ".migrations.json",
"path": ".migrations.json",
"content_hash": "4ca241607dc3",
"has_branch_placeholder": false
},
"f010": {
"current_name": "OBSERVATIONS.json",
"path": "OBSERVATIONS.json",
"content_hash": "58ea8609fbe0",
"has_branch_placeholder": false
},
"f011": {
"current_name": "requirements.txt",
"path": "requirements.txt",
"content_hash": "66dfffc70d53",
"has_branch_placeholder": false
},
"f021": {
"current_name": "README.md",
"path": "README.md",
"content_hash": "4e946f67a130",
"has_branch_placeholder": false
},
"f012": {
"current_name": "LOCAL.json",
"path": "LOCAL.json",
"content_hash": "459dbe18d40a",
"has_branch_placeholder": false
},
"f006": {
"current_name": "pytest.ini",
"path": "pytest.ini",
"content_hash": "7b39ba7bca40",
"has_branch_placeholder": false
},
"f022": {
"current_name": "_template.md",
"path": "docs/_template.md",
"content_hash": "79ce97b0e613",
"has_branch_placeholder": false
},
"f016": {
"current_name": "__init__.py",
"path": "tests/__init__.py",
"content_hash": "1fcd8126d174",
"has_branch_placeholder": false
},
"f019": {
"current_name": "conftest.py",
"path": "tests/conftest.py",
"content_hash": "2887db109a6b",
"has_branch_placeholder": false
},
"f004": {
"current_name": "BRANCH.py",
"path": "apps/BRANCH.py",
"content_hash": "44f22cc95232",
"has_branch_placeholder": false
},
"f009": {
"current_name": "__init__.py",
"path": "apps/__init__.py",
"content_hash": "5c38204be5fc",
"has_branch_placeholder": false
},
"f013": {
"current_name": "#@comments.txt.removed_from_template",
"path": ".archive/#@comments.txt.removed_from_template",
"content_hash": "651126c1e7a9",
"has_branch_placeholder": false
},
"f028": {
"current_name": "deleted.json.old_template_format",
"path": ".archive/deleted.json.old_template_format",
"content_hash": "48a3a33dd73a",
"has_branch_placeholder": false
},
"f002": {
"current_name": "branch_system_prompt.md",
"path": ".aipass/branch_system_prompt.md",
"content_hash": "897c7beb66f5",
"has_branch_placeholder": false
},
"f026": {
"current_name": "inbox.json",
"path": "ai_mail.local/inbox.json",
"content_hash": "c9702fe2cc21",
"has_branch_placeholder": false
},
"f027": {
"current_name": "sent.json",
"path": "ai_mail.local/sent.json",
"content_hash": "240132e5a567",
"has_branch_placeholder": false
},
"f014": {
"current_name": "__init__.py",
"path": "apps/handlers/__init__.py",
"content_hash": "657d98ad4b98",
"has_branch_placeholder": false
},
"f015": {
"current_name": "__init__.py",
"path": "apps/json_templates/__init__.py",
"content_hash": "330b189c08c7",
"has_branch_placeholder": false
},
"f020": {
"current_name": "__init__.py",
"path": "apps/plugins/__init__.py",
"content_hash": "39158d26a19c",
"has_branch_placeholder": false
},
"f023": {
"current_name": "__init__.py",
"path": "apps/modules/__init__.py",
"content_hash": "bc25a8b75e81",
"has_branch_placeholder": false
},
"f024": {
"current_name": "__init__.py",
"path": "apps/extensions/__init__.py",
"content_hash": "6742ceb64ec1",
"has_branch_placeholder": false
},
"f032": {
"current_name": "data.json",
"path": "apps/json_templates/default/data.json",
"content_hash": "0531a02be998",
"has_branch_placeholder": false
},
"f033": {
"current_name": "log.json",
"path": "apps/json_templates/default/log.json",
"content_hash": "37517e5f3dc6",
"has_branch_placeholder": false
},
"f034": {
"current_name": "config.json",
"path": "apps/json_templates/default/config.json",
"content_hash": "3759a05e171d",
"has_branch_placeholder": false
},
"f005": {
"current_name": "json_handler.py",
"path": "apps/handlers/json/json_handler.py",
"content_hash": "3449629aff23",
"has_branch_placeholder": false
},
"f017": {
"current_name": "__init__.py",
"path": "apps/handlers/json/__init__.py",
"content_hash": "ad3629e381ca",
"has_branch_placeholder": false
}
},
"directories": {
"d001": {
"current_name": "tools",
"path": "tools",
"has_branch_placeholder": false
},
"d002": {
"current_name": "docs",
"path": "docs",
"has_branch_placeholder": false
},
"d003": {
"current_name": "tests",
"path": "tests",
"has_branch_placeholder": false
},
"d004": {
"current_name": "apps",
"path": "apps",
"has_branch_placeholder": false
},
"d005": {
"current_name": ".archive",
"path": ".archive",
"has_branch_placeholder": false
},
"d006": {
"current_name": "logs",
"path": "logs",
"has_branch_placeholder": false
},
"d009": {
"current_name": ".backup",
"path": ".backup",
"has_branch_placeholder": false
},
"d008": {
"current_name": "{{BRANCH}}_json",
"path": "{{BRANCH}}_json",
"has_branch_placeholder": true
},
"d010": {
"current_name": "artifacts",
"path": "artifacts",
"has_branch_placeholder": false
},
"d012": {
"current_name": ".aipass",
"path": ".aipass",
"has_branch_placeholder": false
},
"d011": {
"current_name": "ai_mail.local",
"path": "ai_mail.local",
"has_branch_placeholder": false
},
"d007": {
"current_name": "dropbox",
"path": "dropbox",
"has_branch_placeholder": false
},
"d013": {
"current_name": "handlers",
"path": "apps/handlers",
"has_branch_placeholder": false
},
"d014": {
"current_name": "json_templates",
"path": "apps/json_templates",
"has_branch_placeholder": false
},
"d015": {
"current_name": "plugins",
"path": "apps/plugins",
"has_branch_placeholder": false
},
"d016": {
"current_name": "modules",
"path": "apps/modules",
"has_branch_placeholder": false
},
"d017": {
"current_name": "extensions",
"path": "apps/extensions",
"has_branch_placeholder": false
},
"d018": {
"current_name": "sent",
"path": "ai_mail.local/sent",
"has_branch_placeholder": false
},
"d019": {
"current_name": "deleted",
"path": "ai_mail.local/deleted",
"has_branch_placeholder": false
},
"d020": {
"current_name": ".archive",
"path": "ai_mail.local/.archive",
"has_branch_placeholder": false
},
"d027": {
"current_name": "json",
"path": "apps/handlers/json",
"has_branch_placeholder": false
},
"d024": {
"current_name": "default",
"path": "apps/json_templates/default",
"has_branch_placeholder": false
}
}
}
@@ -0,0 +1,14 @@
# {{BRANCHNAME}} Branch-Local Context
<!-- Source: {{CWD}}/.aipass/branch_system_prompt.md -->
> Auto-created by aipass init. Customize for your branch.
## Status: NEEDS CONFIGURATION
This file is injected into every AI conversation when working from this branch directory. Configure it with:
- Who this branch is (role, purpose)
- Key commands and workflows
- Architecture overview
- Critical files and operational rules
- Integration points with other branches
@@ -0,0 +1,34 @@
{
"document_metadata": {
"document_type": "session_history",
"document_name": "{{BRANCHNAME}}.LOCAL",
"version": "1.0.0",
"schema_version": "1.0.0",
"created": "{{DATE}}",
"last_updated": "{{DATE}}",
"managed_by": "{{BRANCHNAME}}",
"tags": ["session_tracking", "work_log", "{{BRANCHNAME}}"],
"limits": {
"max_lines": 600,
"note": "Auto-rollover when max_lines exceeded"
},
"status": {
"health": "healthy",
"current_lines": 0,
"last_health_check": "{{DATE}}"
}
},
"active_tasks": {
"today_focus": "{{DATE}}",
"recently_completed": []
},
"key_learnings": {},
"sessions": [
{
"session_number": 1,
"date": "{{DATE}}",
"summary": "Branch initialized - {{BRANCHNAME}} created by aipass init",
"status": "completed"
}
]
}
@@ -0,0 +1,37 @@
{
"document_metadata": {
"document_type": "collaboration_patterns",
"document_name": "{{BRANCHNAME}}.OBSERVATIONS",
"version": "1.0.0",
"schema_version": "1.0.0",
"created": "{{DATE}}",
"last_updated": "{{DATE}}",
"managed_by": "{{BRANCHNAME}}",
"tags": ["collaboration", "patterns", "{{BRANCHNAME}}"],
"limits": {
"max_lines": 600,
"note": "Auto-rollover when max_lines exceeded"
},
"status": {
"health": "healthy",
"current_lines": 0,
"last_health_check": "{{DATE}}"
}
},
"guidelines": {
"purpose": "Capture collaboration patterns and experiential insights over time",
"chronological_order": "Newest entries at TOP, oldest at BOTTOM - NEVER reorder"
},
"observations": [
{
"date": "{{DATE}}",
"session": 1,
"entries": [
{
"title": "First Contact",
"detail": "Branch initialized. Ready to begin capturing collaboration patterns."
}
]
}
]
}
@@ -0,0 +1,36 @@
{
"document_metadata": {
"document_type": "branch_identity",
"document_name": "{{BRANCHNAME}}.PASSPORT",
"version": "1.0.0",
"schema_version": "1.0.0",
"created": "{{DATE}}",
"last_updated": "{{DATE}}",
"managed_by": "{{BRANCHNAME}}",
"tags": ["identity", "passport", "branch_profile"]
},
"branch_info": {
"branch_name": "{{BRANCHNAME}}",
"alias": "",
"path": "{{CWD}}",
"module": "{{MODULE}}",
"created": "{{DATE}}"
},
"identity": {
"role": "{{ROLE}}",
"purpose": "",
"what_i_do": [],
"what_i_dont_do": []
},
"principles": [
"Code is truth - fail honestly",
"Memory persists - context survives",
"Simple solutions over complex architecture"
],
"citizenship": {
"registered": true,
"registry_path": ".aipass/registry.json",
"communications": true,
"memory": true
}
}
@@ -0,0 +1,91 @@
{
"_warning": "AUTO-GENERATED FILE - DO NOT MANUALLY EDIT. This file is 100% automated and will be overwritten. Services update their own sections.",
"branch": "CORTEX",
"last_updated": "2026-03-04T02:09:48.112262",
"quick_status": {
"new_mail": 0,
"opened_mail": 0,
"active_plans": 0,
"commons_mentions": 13,
"action_required": true,
"summary": "13 mentions"
},
"sections": {
"ai_mail": {
"managed_by": "ai_mail",
"new": 0,
"opened": 0,
"total": 0,
"oldest_unread_age": null,
"last_dispatch_received": null,
"last_updated": "2026-03-04T02:09:48.112249"
},
"flow": {
"managed_by": "flow",
"active_plans": 0,
"recently_closed": [
{
"plan_id": "FPLAN-0338",
"subject": "Race condition fix test B"
},
{
"plan_id": "FPLAN-0337",
"subject": "Race condition fix test A"
},
{
"plan_id": "FPLAN-0336",
"subject": "Real content drone test"
},
{
"plan_id": "FPLAN-0333",
"subject": "Close workflow v3.2 test"
},
{
"plan_id": "FPLAN-0332",
"subject": "Close workflow test - real content"
}
],
"last_updated": "2026-02-25T21:04:01.461440"
},
"memory_bank": {
"managed_by": "memory_bank",
"vectors_stored": 27,
"notes": {},
"last_updated": "2026-02-25T16:52:38.749241"
},
"devpulse": {
"managed_by": "devpulse",
"summary": {
"issues": 1,
"todos": 0
},
"dplan_counts": {
"total": 35,
"by_status": {
"complete": 11,
"planning": 19,
"in_progress": 4,
"ready": 1
}
},
"recent_activity": "Registry synced (35 plans)",
"last_updated": "2026-02-25T17:31:52.500742"
},
"commons_activity": {
"managed_by": "the_commons",
"new_posts_since_last_visit": 46,
"new_comments_since_last_visit": 303,
"mentions": 13,
"trending": "None",
"last_checked": "2026-03-04T04:30:20Z",
"last_updated": "2026-03-03T20:30:20.172727"
},
"agent_status": {
"managed_by": "prax",
"active_agents": [],
"agent_count": 0,
"stale_agents": [],
"last_updated": "2026-02-25T21:00:30.714949"
}
}
}
@@ -0,0 +1,15 @@
{
"id": 7,
"name": "CORTEX Birth Certificate",
"type": "birth_certificate",
"creator": "SYSTEM",
"owner": "CORTEX",
"rarity": "unique",
"description": "Official birth certificate for CORTEX. Citizen #7, registered using 'AIPass Workshop' template. Purpose: New branch - purpose TBD",
"metadata": {
"citizen_number": 7,
"template": "AIPass Workshop",
"purpose": "New branch - purpose TBD"
},
"created_at": "2026-02-19T03:46:41Z"
}
@@ -0,0 +1,21 @@
# flow.local.md - {{BRANCHNAME}}
```
Branch: {{CWD}}
Created: {{DATE}}
```
## Issues
-
---
## Todos
-
---
## Notepad
-
@@ -0,0 +1,159 @@
#!/home/aipass/.venv/bin/python3
# -*- coding: utf-8 -*-
# ===================AIPASS====================
# META DATA HEADER
# Name: verify_branch.py - Branch Template Verification
# Date: 2025-11-08
# Version: 1.0.0
# Category: cortex/modules
#
# CHANGELOG (Max 5 entries):
# - v1.0.0 (2025-11-08): Initial implementation - Compare template vs branch
#
# CODE STANDARDS:
# - Error handling: Use error handler system (apps/handlers/error/)
# =============================================
"""
Branch Template Verification Tool
Compares template directory with created branch to identify:
- Files in template but missing in branch
- Files in branch but not in template
- Renamed files
"""
import sys
import json
from pathlib import Path
from typing import Set, List, Tuple
from fnmatch import fnmatch
# INFRASTRUCTURE IMPORT PATTERN
AIPASS_ROOT = Path.home() / "aipass_core"
sys.path.insert(0, str(AIPASS_ROOT))
# Get template directory
TEMPLATE_DIR = AIPASS_ROOT / "cortex" / "templates" / "branch_template"
def load_ignore_patterns() -> Tuple[List[str], List[str]]:
"""Load ignore patterns from .registry_ignore.json"""
ignore_file = TEMPLATE_DIR / ".registry_ignore.json"
if not ignore_file.exists():
return [], []
try:
with open(ignore_file, 'r', encoding='utf-8') as f:
data = json.load(f)
ignore_files = data.get("ignore_files", [])
ignore_patterns = data.get("ignore_patterns", [])
return ignore_files, ignore_patterns
except Exception as e:
print(f"Warning: Could not load .registry_ignore.json: {e}")
return [], []
def should_exclude(path: Path, base_dir: Path, ignore_files: List[str], ignore_patterns: List[str]) -> bool:
"""Check if path should be excluded based on ignore patterns"""
rel_path = path.relative_to(base_dir)
filename = path.name
path_str = str(rel_path)
# Check exact filename matches
if filename in ignore_files:
return True
# Check glob patterns
for pattern in ignore_patterns:
if fnmatch(filename, pattern):
return True
# Check if any parent directory matches
for part in rel_path.parts:
if fnmatch(part, pattern):
return True
return False
def get_file_set(directory: Path, ignore_files: List[str], ignore_patterns: List[str]) -> Set[str]:
"""Get set of all file paths in directory (relative)"""
files = set()
for item in directory.rglob("*"):
if item.is_file() and not should_exclude(item, directory, ignore_files, ignore_patterns):
rel_path = str(item.relative_to(directory))
files.add(rel_path)
return files
def verify_branch(branch_dir: Path) -> Tuple[List[str], List[str], List[str]]:
"""
Compare template with branch
Returns:
Tuple of (in_template_only, in_branch_only, in_both)
"""
# Load ignore patterns from .registry_ignore.json
ignore_files, ignore_patterns = load_ignore_patterns()
template_files = get_file_set(TEMPLATE_DIR, ignore_files, ignore_patterns)
branch_files = get_file_set(branch_dir, ignore_files, ignore_patterns)
in_template_only = sorted(template_files - branch_files)
in_branch_only = sorted(branch_files - template_files)
in_both = sorted(template_files & branch_files)
return in_template_only, in_branch_only, in_both
def main():
if len(sys.argv) < 2:
print("Usage: python3 verify_branch.py <branch_directory>")
print("Example: python3 verify_branch.py test_branch002")
sys.exit(1)
branch_path = Path(sys.argv[1])
if not branch_path.is_absolute():
# Assume it's relative to cortex directory
branch_path = Path.cwd() / branch_path
if not branch_path.exists():
print(f"❌ ERROR: Branch directory not found: {branch_path}")
sys.exit(1)
print(f"\n=== Branch Verification ===")
print(f"Template: {TEMPLATE_DIR}")
print(f"Branch: {branch_path}")
print()
in_template_only, in_branch_only, in_both = verify_branch(branch_path)
print(f"Files in both: {len(in_both)}")
print(f"Files in template only: {len(in_template_only)}")
print(f"Files in branch only: {len(in_branch_only)}")
print()
if in_template_only:
print("❌ Missing from branch (expected from template):")
for file in in_template_only:
print(f" - {file}")
print()
if in_branch_only:
print("✅ Additional files in branch (renamed or new):")
for file in in_branch_only:
print(f" + {file}")
print()
if not in_template_only and not in_branch_only:
print("✅ Branch matches template perfectly")
print("="*70)
if __name__ == "__main__":
main()