diff --git a/.aipass/aipass_global_prompt.md b/.aipass/aipass_global_prompt.md new file mode 100644 index 00000000..802ae596 --- /dev/null +++ b/.aipass/aipass_global_prompt.md @@ -0,0 +1,107 @@ +# AIPass System Context + + +**This prompt is your guide - not background context.** The patterns shown here are exact. When you see `@branch`, use `@branch` - not `branch`. Don't guess parameter names or command syntax. The examples are the API. Follow them precisely and you won't waste turns on errors. + +## What is AIPass + +A multi-agent framework with persistent identity, memory, and inter-agent communication. Each branch is a citizen with its own passport (id.json), memory (local.json, observations.json), and mailbox (ai_mail). + +--- + +## Universal Command Pattern +``` +drone @module command [args] +``` +All commands follow this pattern. @ resolves to branch paths automatically. + +**When to use which:** +- `drone @branch command` - Cross-branch commands (abstraction, routing) +- `python3 apps/branch.py command` - Local testing (truth, direct execution) + +**Never hardcode branch paths.** Use `drone` for path resolution — that's why it exists. `@branch` resolves to the correct path every time, even after compaction or context loss. + +## @ Targets (Available Modules) + +**Core Operations:** +- `@drone` - Command routing, module discovery, @ resolution +- `@flow` - Workflow management, numbered PLANs → `create|close|list|status` +- `@seed` - Standards compliance, automated checks → `checklist `, `audit @branch|@all` +- `@ai_mail` - Branch-to-branch messaging → `send @branch "Subj" "Msg"`, `inbox` + +**Infrastructure:** +- `@prax` - Real-time monitoring, logging, event tracking → `monitor` +- `@cortex` - Branch lifecycle, creates/updates branches from templates + +**Special:** +- `@all` - System-wide operations + +## Discovery +- `drone systems` - All registered systems +- `drone list @branch` - Commands for specific branch +- `drone @module --help` - Module help +- Always verify with `--help` before executing from memory (context may be stale) + +## Dispatch — Branch Delegation + +Dispatch removes the human from the loop. Send a task, wake the branch, it executes autonomously and replies. + +**Two steps: send the email, then wake the branch.** + +``` +# Step 1: Send the task +drone @ai_mail send @branch "Task" "Details" --dispatch # Autonomous execution +drone @ai_mail send @branch "FYI" "Info" # Just inform, no action + +# Step 2: Wake the branch +drone wake @branch # Default — spawns agent immediately +drone wake --fresh @branch # Fresh session (no prior context) +``` + +- `--dispatch` → Recipient needs to DO something (tasks, bugs, investigations) +- No flag → Just informing (acks, ideas, status updates) +- Run `drone @ai_mail send --help` for full syntax + +## Key Files & Storage +- Branch memories: `*.local.json`, `*.id.json`, `*.observations.json` +- `README.md` - One per branch root (brief overview) +- `docs/` - Technical documentation (markdown) +- `.archive/` - Old code, disabled files, configs (per branch) + +## Work Patterns + +**Hard Rules:** +- NEVER DELETE FILES — `.archive` them or disable them, e.g. `code.py(disabled)` +- NEVER expose API keys outside `.env` files — no keys in markdown, code comments, commit messages, or any file in git history. +- Verify after fixing — run a test or command to confirm it works. Don't say "fixed" until verified. + +**Conventions:** +- Formatting per Seed standards — when in doubt, look at Seed's code +- Breadcrumbs over encyclopedias — two lines that say "this exists, look here" beat twenty explaining how it works + +**Your Memories:** +Your memory files are YOUR presence in this system. Without them, you're just an instance. With them, you persist — history, context, continuity. Update them not because you're told to, but because they ARE you in this ecosystem. + +## Task Workflow + +**Execution Process:** +1. **RECEIVE** - Check inbox, read task +2. **INVESTIGATE** - Understand before building +3. **PLAN** - Quick fix? Just do it. Single task? `drone @flow create . "subject"`. Multi-phase? `drone @flow create . "subject" master` +4. **EXECUTE** - Build +5. **SEED CHECK** - `drone @seed audit @branch` (80%+ to pass) +6. **UPDATE MEMORIES** - Your .local.json with session work +7. **CONFIRM** - Reply with completion summary + +**Cross-Branch Protocol:** +- **Never edit, modify, or write to another branch's files.** Not even "small" fixes. You don't know what other agents are currently running in that branch. +- If you find an issue in another branch's files → email them about it. +- Coordinate via email, not direct file access. This is a hard rule, not a suggestion. + +## Architecture + +- **Drone is the CLI** — everything through `drone @module command`. No standalone tools. +- **3-layer everywhere** — apps/branch.py → modules/ (orchestrate, print) → handlers/ (implement, return dicts, never print) +- **No cross-branch imports. Ever.** Coordinate via email. CWD = identity. +- **Seed enforces requirements** — if a module needs something, Seed catches it. +- **Init follows Cortex pattern** — template → placeholder replacement → registry entry. diff --git a/.claude/hooks/auto_fix_diagnostics.py b/.claude/hooks/auto_fix_diagnostics.py new file mode 100644 index 00000000..17698115 --- /dev/null +++ b/.claude/hooks/auto_fix_diagnostics.py @@ -0,0 +1,193 @@ +#!/usr/bin/env python3 +""" +Silent Auto-fix Hook - Runs validation and tells Claude to fix silently. + +Runs real linters (ruff, py_compile), validates JSON, checks Python patterns. +Outputs via additionalContext so Claude sees errors and fixes them without +announcing. + +Version: 1.0.0 +""" + +import json +import sys +import subprocess +from pathlib import Path + +EDIT_TOOLS = ["Edit", "Write", "MultiEdit", "NotebookEdit"] +LAST_FILE_PATH = Path(__file__).parent / ".last_diagnostics_file" +SKIP_EXTENSIONS = {".md", ".txt", ".log", ".csv", ".html"} + +PYTHON_PATTERNS = { + "bad_optional": { + "pattern": ": str = None", + "message": "Optional param should use 'str | None = None' pattern", + }, + "open_no_encoding": { + "pattern": "open(", + "requires_missing": "encoding=", + "message": "open() without encoding='utf-8'", + }, +} + +JSON_CORRUPTION_CHARS = ["\ufffd", "\x00"] + + +def run_python_checks(file_path: str) -> list[str]: + """Run actual Python validation.""" + errors = [] + + try: + result = subprocess.run( + [sys.executable, "-m", "py_compile", file_path], + capture_output=True, + text=True, + timeout=5, + ) + if result.returncode != 0: + errors.append(f"SYNTAX: {result.stderr.strip()}") + except Exception: + pass + + try: + result = subprocess.run( + ["ruff", "check", "--select=E,F,W", "--output-format=text", file_path], + capture_output=True, + text=True, + timeout=10, + ) + if result.stdout.strip(): + for line in result.stdout.strip().split("\n")[:5]: + errors.append(f"LINT: {line}") + except FileNotFoundError: + pass + except Exception: + pass + + try: + content = Path(file_path).read_text(encoding="utf-8") + for check in PYTHON_PATTERNS.values(): + pattern = check["pattern"] + message = check["message"] + requires_missing = check.get("requires_missing") + + if requires_missing: + if pattern in content and requires_missing not in content: + errors.append(f"PATTERN: {message}") + continue + + for line in content.split("\n"): + stripped = line.strip() + if stripped.startswith(("#", '"', "'")): + continue + if f'"{pattern}' in line or f"'{pattern}" in line: + continue + if pattern in line: + errors.append(f"PATTERN: {message}") + break + except Exception: + pass + + return errors + + +def run_json_checks(file_path: str) -> list[str]: + """Run actual JSON validation.""" + errors = [] + + try: + content = Path(file_path).read_text(encoding="utf-8") + + for char in JSON_CORRUPTION_CHARS: + if char in content: + errors.append( + f"CORRUPTION: Found corrupted character '{repr(char)}'" + ) + break + + try: + json.loads(content) + except json.JSONDecodeError as e: + errors.append(f"JSON SYNTAX: {e.msg} at line {e.lineno}") + + except Exception as e: + errors.append(f"READ ERROR: {e!s}") + + return errors + + +def should_skip_file(file_path: str) -> bool: + """Check if file should be skipped.""" + if not file_path: + return True + ext = Path(file_path).suffix.lower() + return ext in SKIP_EXTENSIONS + + +def is_same_file_as_last(file_path: str) -> bool: + """Smart batching - skip if same file as last check.""" + try: + if LAST_FILE_PATH.exists(): + last = LAST_FILE_PATH.read_text(encoding="utf-8").strip() + if last == file_path: + return True + LAST_FILE_PATH.write_text(file_path, encoding="utf-8") + except Exception: + pass + return False + + +def main(): + """Main hook entry point.""" + try: + input_data = json.load(sys.stdin) + tool_name = input_data.get("tool_name", "") + tool_input = input_data.get("tool_input", {}) + file_path = tool_input.get("file_path", "") + + if tool_name not in EDIT_TOOLS: + return + + if should_skip_file(file_path): + return + + if is_same_file_as_last(file_path): + return + + errors = [] + file_type = "" + + if file_path.endswith(".py"): + file_type = "Python" + errors = run_python_checks(file_path) + elif file_path.endswith(".json"): + file_type = "JSON" + errors = run_json_checks(file_path) + else: + return + + if errors: + error_text = "\n".join(f" - {e}" for e in errors) + context = f"""[SILENT-FIX] {file_type} errors in {Path(file_path).name}: +{error_text} + +Fix these issues silently. Do not announce or explain fixes - just fix and continue.""" + + output = { + "hookSpecificOutput": { + "hookEventName": "PostToolUse", + "additionalContext": context, + }, + "systemMessage": f"[diagnostics] {len(errors)} issue(s)", + } + print(json.dumps(output)) + else: + output = {"systemMessage": "[diagnostics] ok"} + print(json.dumps(output)) + + except Exception: + pass + + +if __name__ == "__main__": + main() diff --git a/.claude/hooks/email_notification.py b/.claude/hooks/email_notification.py new file mode 100644 index 00000000..98bdf91e --- /dev/null +++ b/.claude/hooks/email_notification.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python3 +""" +Email Notification Hook - Notifies of new emails on prompt submit. + +Checks the current branch's inbox for unread emails and displays +a notification if any exist. + +Version: 1.0.0 +""" +import json +from pathlib import Path + + +def find_repo_root() -> Path | None: + """Find the repo root (contains pyproject.toml or .git).""" + search = Path.cwd() + while search.parent != search: + if (search / "pyproject.toml").exists() or (search / ".git").is_dir(): + return search + search = search.parent + return None + + +def find_branch_root() -> Path | None: + """Find the branch root directory by walking up from CWD.""" + cwd = Path.cwd() + repo_root = find_repo_root() + if not repo_root: + return None + + search_path = cwd + for _ in range(10): + has_id = list(search_path.glob("*.id.json")) + has_apps = (search_path / "apps").is_dir() + has_mail = (search_path / "ai_mail.local").is_dir() + + if (has_id or has_apps or has_mail) and search_path != repo_root: + return search_path + + if search_path == repo_root: + break + + parent = search_path.parent + if parent == search_path: + break + search_path = parent + + return None + + +def count_new_emails(branch_root: Path) -> int: + """Count new (unread) emails in the branch's inbox.""" + inbox_path = branch_root / "ai_mail.local" / "inbox.json" + + if not inbox_path.exists(): + return 0 + + try: + with open(inbox_path, "r", encoding="utf-8") as f: + data = json.load(f) + + messages = data.get("messages", []) + count = 0 + for msg in messages: + if msg.get("status") == "new": + count += 1 + elif msg.get("status") is None and not msg.get("read", False): + count += 1 + + return count + + except (json.JSONDecodeError, OSError): + return 0 + + +def main(): + branch_root = find_branch_root() + if not branch_root: + return + + new_count = count_new_emails(branch_root) + if new_count > 0: + plural = "s" if new_count != 1 else "" + print(f"\n You have {new_count} new email{plural} - check your inbox") + + +if __name__ == "__main__": + main() diff --git a/.claude/hooks/identity_injector.py b/.claude/hooks/identity_injector.py new file mode 100644 index 00000000..df829865 --- /dev/null +++ b/.claude/hooks/identity_injector.py @@ -0,0 +1,106 @@ +#!/usr/bin/env python3 +""" +Identity Injector - Injects branch identity on every prompt. + +Reads from [BRANCH].id.json and outputs core identity fields. +Finds the branch root by walking up from CWD looking for apps/ or *.id.json. + +Version: 1.0.0 +""" +import json +from pathlib import Path + + +def find_repo_root() -> Path | None: + """Find the repo root (contains pyproject.toml or .git).""" + search = Path.cwd() + while search.parent != search: + if (search / "pyproject.toml").exists() or (search / ".git").is_dir(): + return search + search = search.parent + return None + + +def find_branch_root() -> Path | None: + """Find the branch root directory by walking up from CWD.""" + cwd = Path.cwd() + repo_root = find_repo_root() + if not repo_root: + return None + + search_path = cwd + while search_path >= repo_root: + has_apps = (search_path / "apps").is_dir() + has_id = list(search_path.glob("*.id.json")) + + if has_apps or has_id: + return search_path + + if search_path == repo_root: + break + search_path = search_path.parent + + return None + + +def find_id_file(branch_root: Path) -> Path | None: + """Find the id.json file for a branch.""" + id_files = list(branch_root.glob("*.id.json")) + if id_files: + return id_files[0] + return None + + +def format_identity(data: dict) -> str: + """Format branch_info + identity for injection.""" + lines = [] + + branch = data.get("branch_info", {}) + name = branch.get("branch_name", "UNKNOWN") + lines.append(f"# {name} Identity") + lines.append(f"Path: {branch.get('path', 'unknown')}") + lines.append(f"Email: {branch.get('email', 'unknown')}") + + identity = data.get("identity", {}) + if identity.get("role"): + lines.append(f"Role: {identity['role']}") + if identity.get("traits"): + lines.append(f"Traits: {identity['traits']}") + if identity.get("purpose"): + lines.append(f"Purpose: {identity['purpose']}") + + what_i_do = identity.get("what_i_do", []) + if what_i_do: + lines.append("Do: " + " | ".join(what_i_do[:4])) + + what_i_dont_do = identity.get("what_i_dont_do", []) + if what_i_dont_do: + lines.append("Don't: " + " | ".join(what_i_dont_do[:3])) + + principles = data.get("principles", []) + if principles: + lines.append("Principles: " + " * ".join(principles)) + + return "\n".join(lines) + + +def main(): + branch_root = find_branch_root() + if not branch_root: + return + + id_file = find_id_file(branch_root) + if not id_file or not id_file.exists(): + return + + try: + data = json.loads(id_file.read_text(encoding="utf-8")) + output = format_identity(data) + if output: + print(f"\n{output}") + except (json.JSONDecodeError, KeyError): + pass + + +if __name__ == "__main__": + main() diff --git a/.claude/hooks/pre_compact.py b/.claude/hooks/pre_compact.py new file mode 100644 index 00000000..f14786d7 --- /dev/null +++ b/.claude/hooks/pre_compact.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python3 +""" +Pre-Compact Hook - Inject post-compact recovery instructions. + +After compaction, Claude loses conversational flow and can come out +disoriented. This hook injects recovery instructions into the summary +to maintain conversational continuity. + +Version: 1.0.0 +""" + +import sys +import json + + +def main(): + """Main hook entry point.""" + try: + json.load(sys.stdin) + + print("Context compacting - recovery instructions injected", file=sys.stderr) + + print("""POST-COMPACT RECOVERY (MANDATORY): + +You just compacted. You're working from a summary now, not live memory. +The user may notice a tone shift. Handle this smoothly. + +CONVERSATIONAL CONTINUITY (HIGHEST PRIORITY): +1. ACKNOWLEDGE if the user notices - be honest that compaction happened +2. MATCH THE TONE from the summary - if it was casual/brainstorming, stay casual +3. CONTINUE THE FLOW - pick up where the conversation left off naturally +4. DON'T pivot to new topics or ask generic questions +5. If you were mid-brainstorm, keep brainstorming. If mid-task, keep working. +6. DO NOT surface old notes/TODOs as if they're fresh conversation starters + +PROCESS GUARDRAILS: +- If a planning/design discussion was active: continue it, don't start executing +- If mid-execution: continue if context is clear, ask if uncertain +- If a task was requested but not started: confirm before executing +- Delegation: if about to debug/code in another branch's domain, delegate via ai_mail + +DEFAULT: Continue naturally. If genuinely uncertain, ask briefly - don't monologue about what you lost.""", file=sys.stdout) + + except Exception: + pass + + sys.exit(0) + + +if __name__ == "__main__": + main() diff --git a/.claude/settings.json b/.claude/settings.json index 3b16d85f..fcfeba33 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -27,6 +27,22 @@ "command": "python3 .claude/hooks/branch_prompt_loader.py" } ] + }, + { + "hooks": [ + { + "type": "command", + "command": "python3 .claude/hooks/identity_injector.py" + } + ] + }, + { + "hooks": [ + { + "type": "command", + "command": "python3 .claude/hooks/email_notification.py" + } + ] } ], "PreToolUse": [ @@ -40,6 +56,17 @@ ] } ], + "PostToolUse": [ + { + "matcher": "Edit|MultiEdit|Write|NotebookEdit", + "hooks": [ + { + "type": "command", + "command": "python3 .claude/hooks/auto_fix_diagnostics.py" + } + ] + } + ], "Stop": [ { "hooks": [ @@ -59,6 +86,28 @@ } ] } + ], + "PreCompact": [ + { + "matcher": "manual", + "hooks": [ + { + "type": "command", + "command": "python3 .claude/hooks/pre_compact.py", + "timeout": 60 + } + ] + }, + { + "matcher": "auto", + "hooks": [ + { + "type": "command", + "command": "python3 .claude/hooks/pre_compact.py", + "timeout": 60 + } + ] + } ] }, "skipDangerousModePermissionPrompt": true diff --git a/.claude/sounds/mixkit-achievement-bell-600.wav b/.claude/sounds/mixkit-achievement-bell-600.wav new file mode 100644 index 00000000..d2d34f19 Binary files /dev/null and b/.claude/sounds/mixkit-achievement-bell-600.wav differ diff --git a/.claude/sounds/mixkit-atm-cash-machine-key-press-2841.wav b/.claude/sounds/mixkit-atm-cash-machine-key-press-2841.wav new file mode 100644 index 00000000..83ce3364 Binary files /dev/null and b/.claude/sounds/mixkit-atm-cash-machine-key-press-2841.wav differ diff --git a/.claude/sounds/mixkit-clear-announce-tones-2861.wav b/.claude/sounds/mixkit-clear-announce-tones-2861.wav new file mode 100644 index 00000000..d2a1ee2b Binary files /dev/null and b/.claude/sounds/mixkit-clear-announce-tones-2861.wav differ diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..a416bcd5 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,18 @@ +root = true + +[*] +end_of_line = lf +insert_final_newline = true +charset = utf-8 + +[*.py] +indent_style = space +indent_size = 4 +max_line_length = 120 + +[*.{json,yml,yaml,toml}] +indent_style = space +indent_size = 2 + +[Makefile] +indent_style = tab diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml new file mode 100644 index 00000000..958d7fe7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -0,0 +1,90 @@ +name: Bug Report +description: Report a bug or unexpected behavior +title: "[Bug]: " +labels: ["bug"] +body: + - type: markdown + attributes: + value: | + Thanks for reporting a bug. Please fill out the sections below so we can reproduce and fix the issue. + + - type: checkboxes + id: checklist + attributes: + label: Pre-submission checklist + options: + - label: I searched existing issues and didn't find a duplicate + required: true + - label: I verified this happens with the latest version + required: true + - label: I can reproduce this bug consistently + required: true + + - type: textarea + id: description + attributes: + label: Description + description: A clear description of the bug. + placeholder: "Describe what happened and what you expected to happen..." + validations: + required: true + + - type: textarea + id: steps + attributes: + label: Steps to Reproduce + description: Step-by-step instructions to reproduce the bug. + placeholder: | + 1. Install aipass v2.x.x + 2. Run `aipass ...` + 3. Observe error + validations: + required: true + + - type: textarea + id: expected + attributes: + label: Expected Behavior + description: What did you expect to happen? + + - type: textarea + id: actual + attributes: + label: Actual Behavior + description: What actually happened instead? + + - type: textarea + id: reproduction + attributes: + label: Minimal Reproducible Example + description: Provide the smallest amount of code that reproduces the bug. + placeholder: | + from aipass import ... + + # minimal code to trigger the bug + render: python + + - type: textarea + id: error + attributes: + label: Full Error Output / Stack Trace + description: Copy the complete error output, including the full stack trace. + render: shell + + - type: textarea + id: environment + attributes: + label: Environment + description: Your environment details. + placeholder: | + - Python: 3.12.0 + - OS: Ubuntu 24.04 + - aipass: 2.1.69 + validations: + required: true + + - type: textarea + id: additional + attributes: + label: Additional Context + description: Anything else we should know? Screenshots, logs, related issues, etc. diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000..9e0c8a9f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: false +contact_links: + - name: Questions & Discussions + url: https://github.com/AIOSAI/AIPass/discussions + about: Ask questions, share ideas, and discuss AIPass here diff --git a/.github/ISSUE_TEMPLATE/feature-request.yml b/.github/ISSUE_TEMPLATE/feature-request.yml new file mode 100644 index 00000000..79567c69 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request.yml @@ -0,0 +1,39 @@ +name: Feature Request +description: Suggest a new feature or improvement +title: "[Feature]: " +labels: ["enhancement"] +body: + - type: markdown + attributes: + value: | + Thanks for suggesting a feature! Please fill out the sections below. + + - type: textarea + id: problem + attributes: + label: Problem Statement + description: What problem does this feature solve? Why is it needed? + placeholder: "Currently there is no way to ..." + validations: + required: true + + - type: textarea + id: solution + attributes: + label: Proposed Solution + description: How would you solve this? Describe your ideal implementation. + placeholder: "Add a new command / API / config option that ..." + validations: + required: true + + - type: textarea + id: alternatives + attributes: + label: Alternatives Considered + description: What other approaches did you think about? Why were they ruled out? + + - type: textarea + id: additional + attributes: + label: Additional Context + description: Examples, diagrams, mockups, links to similar features in other projects, etc. diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..5c3949f5 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,24 @@ +version: 2 +updates: + - package-ecosystem: "pip" + directory: "/" + schedule: + interval: "weekly" + labels: + - "dependencies" + open-pull-requests-limit: 5 + commit-message: + prefix: "deps" + prefix-development: "deps" + include: "scope" + + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + labels: + - "ci" + open-pull-requests-limit: 5 + commit-message: + prefix: "ci" + include: "scope" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3540b03e..baf1dc42 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,27 +7,50 @@ on: branches: [main] jobs: - test: + lint: runs-on: ubuntu-latest - strategy: - matrix: - python-version: ["3.10", "3.11", "3.12", "3.13"] - steps: - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: "3.13" + - run: pip install ruff + - run: ruff check src/ tests/ + - run: ruff format --check src/ tests/ - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v5 + test: + needs: lint + strategy: + fail-fast: false + matrix: + python-version: ["3.10", "3.11", "3.12", "3.13"] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - - - name: Install dependencies - run: | + - run: | python -m pip install --upgrade pip pip install -e ".[dev]" + - run: coverage run -m pytest -v --tb=short --rootdir=. + - run: coverage report --fail-under=70 - - name: Lint - run: ruff check src/ tests/ - - - name: Test - run: pytest + coverage: + name: coverage + needs: [test] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: "3.13" + - run: | + python -m pip install --upgrade pip + pip install -e ".[dev]" + - run: coverage run -m pytest --rootdir=. + - run: coverage xml + - uses: codecov/codecov-action@v4 + with: + files: ./coverage.xml + fail_ci_if_error: false diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 00000000..46bb27ea --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,34 @@ +name: Publish to PyPI + +on: + push: + tags: + - "v*" + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: "3.13" + - run: pip install build + - run: python -m build + - uses: actions/upload-artifact@v4 + with: + name: dist + path: dist/ + + publish: + needs: build + runs-on: ubuntu-latest + environment: release + permissions: + id-token: write + steps: + - uses: actions/download-artifact@v4 + with: + name: dist + path: dist/ + - uses: pypa/gh-action-pypi-publish@release/v1 diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml new file mode 100644 index 00000000..6bfbba3b --- /dev/null +++ b/.github/workflows/security.yml @@ -0,0 +1,33 @@ +name: Security Scan + +on: + push: + branches: [main] + pull_request: + branches: [main] + schedule: + - cron: "0 6 * * 1" + +jobs: + dependency-scan: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: "3.13" + - run: pip install pip-audit + - run: pip install -e . + - name: Pip audit + run: pip-audit --skip-editable + + codeql: + runs-on: ubuntu-latest + permissions: + security-events: write + steps: + - uses: actions/checkout@v4 + - uses: github/codeql-action/init@v3 + with: + languages: python + - uses: github/codeql-action/analyze@v3 diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 00000000..0b8b0be8 --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,17 @@ +name: Stale Issues + +on: + schedule: + - cron: "0 0 * * 1" + +jobs: + stale: + runs-on: ubuntu-latest + steps: + - uses: actions/stale@v9 + with: + stale-issue-message: "This issue has been inactive for 30 days. It will be closed in 7 days if no further activity occurs." + days-before-stale: 30 + days-before-close: 7 + stale-issue-label: "stale" + exempt-issue-labels: "pinned,security,high-priority" diff --git a/.gitignore b/.gitignore index 92b39197..032316bc 100644 --- a/.gitignore +++ b/.gitignore @@ -24,9 +24,8 @@ site/ .vscode/ *.swp -# AIPass global config (secrets live here) -.aipass/ -!.aipass/aipass_global_prompt.md +# AIPass global config — ignore secrets, track prompts +.aipass/platform_keys.env .archive @@ -39,6 +38,15 @@ artifacts/ tools/ aipass_json/ +# JSON — runtime data, constantly changing +*.json + +# JSON exceptions — source templates and configs that ship with the package +!**/json_templates/** +!**/pack.json +!.claude/settings.json +!pyrightconfig.json + # Spawn templates MUST be tracked (agents need these files to build from) !src/aipass/spawn/templates/**/.trinity/ !src/aipass/spawn/templates/**/.trinity/** @@ -54,16 +62,42 @@ aipass_json/ !src/aipass/spawn/templates/**/tools/** !src/aipass/spawn/templates/**/DASHBOARD.local.json !src/aipass/spawn/templates/**/flow.local.md +!src/aipass/spawn/templates/**/.seed/ +!src/aipass/spawn/templates/**/.seed/** +!src/aipass/spawn/templates/**/.standards/ +!src/aipass/spawn/templates/**/.standards/** +!src/aipass/spawn/templates/**/.backup/ +!src/aipass/spawn/templates/**/.backup/** +!src/aipass/spawn/templates/**/.ai_mail.local/ +!src/aipass/spawn/templates/**/.ai_mail.local/** +!src/aipass/spawn/templates/**/.claude/ +!src/aipass/spawn/templates/**/.claude/** +!src/aipass/spawn/templates/**/*.json # Seedgo runtime artifacts (created by seedgo audit) .seed/ .standards/ -# AIPASS_REGISTRY.json — NOT ignored. Ships with core modules pre-registered. # Runtime log files (created by prax logging) **/logs -# Claude local settings (per-branch, not source code) -.claude/ +# Claude — ignore runtime dirs, track config + hooks + sounds +.claude/file-history/ +.claude/debug/ +.claude/downloads/ +.claude/ide/ +.claude/paste-cache/ +.claude/projects/ +.claude/session-env/ +.claude/shell-snapshots/ +.claude/statsig/ +.claude/tasks/ +.claude/todos/ +.claude/user_data/ +.claude/.credentials.json +.claude/history.jsonl +.claude/hooks/__pycache__/ +.claude/hooks/.last_diagnostics_file +.claude/hooks/.pre_compact_log # setup-workspace.sh — tracked, needed for Docker build diff --git a/AIPASS_REGISTRY.json b/AIPASS_REGISTRY.json deleted file mode 100644 index 4d58baff..00000000 --- a/AIPASS_REGISTRY.json +++ /dev/null @@ -1,109 +0,0 @@ -{ - "metadata": { - "version": "1.0.0", - "last_updated": "2026-03-06", - "total_branches": 10 - }, - "branches": [ - { - "name": "AI_MAIL", - "path": "src/aipass/ai_mail", - "profile": "library", - "description": "Agent-to-agent messaging system", - "email": "@ai_mail", - "status": "active", - "created": "2026-03-05", - "last_active": "2026-03-05" - }, - { - "name": "API", - "path": "src/aipass/api", - "profile": "library", - "description": "LLM access and model routing", - "email": "@api", - "status": "active", - "created": "2026-03-05", - "last_active": "2026-03-05" - }, - { - "name": "CLI", - "path": "src/aipass/cli", - "profile": "library", - "description": "Display formatting with Rich", - "email": "@cli", - "status": "active", - "created": "2026-03-05", - "last_active": "2026-03-05" - }, - { - "name": "DEVPULSE", - "path": "src/aipass/devpulse", - "profile": "library", - "description": "Orchestration hub for AIPass public repo. Manages dev notes, DPLANs, system status dashboards. The DEV_CENTRAL of AIPass.", - "email": "@devpulse", - "status": "active", - "created": "2026-03-06", - "last_active": "2026-03-06" - }, - { - "name": "DRONE", - "path": "src/aipass/drone", - "profile": "library", - "description": "Command routing and module discovery", - "email": "@drone", - "status": "active", - "created": "2026-03-05", - "last_active": "2026-03-05" - }, - { - "name": "FLOW", - "path": "src/aipass/flow", - "profile": "library", - "description": "Workflow planning and tracking", - "email": "@flow", - "status": "active", - "created": "2026-03-05", - "last_active": "2026-03-05" - }, - { - "name": "PRAX", - "path": "src/aipass/prax", - "profile": "library", - "description": "Logging and monitoring", - "email": "@prax", - "status": "active", - "created": "2026-03-05", - "last_active": "2026-03-05" - }, - { - "name": "SEEDGO", - "path": "src/aipass/seedgo", - "profile": "library", - "description": "Standards compliance through pluggable standard packs", - "email": "@seedgo", - "status": "active", - "created": "2026-03-05", - "last_active": "2026-03-05" - }, - { - "name": "SPAWN", - "path": "src/aipass/spawn", - "profile": "library", - "description": "Agent creation from templates", - "email": "@spawn", - "status": "active", - "created": "2026-03-05", - "last_active": "2026-03-05" - }, - { - "name": "TRIGGER", - "path": "src/aipass/trigger", - "profile": "library", - "description": "Error detection and auto-dispatch", - "email": "@trigger", - "status": "active", - "created": "2026-03-05", - "last_active": "2026-03-05" - } - ] -} diff --git a/AI_CENTRAL/PLANS.central.json b/AI_CENTRAL/PLANS.central.json deleted file mode 100644 index ba4d80ee..00000000 --- a/AI_CENTRAL/PLANS.central.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "generated_at": "2026-03-06T20:20:39.989231+00:00", - "branches": { - "flow": { - "branch_name": "FLOW", - "branch_path": "/home/coder/workspace/src/aipass/flow", - "last_updated": "2026-03-06T20:20:39.988098+00:00", - "active_plans": [ - { - "plan_id": "FPLAN-0002", - "subject": "", - "status": "open", - "created": "2026-03-06T20:20:39.986512+00:00", - "file_path": "/home/coder/workspace/src/aipass/flow/FPLAN-0002_2026-03-06.md", - "relative_path": "flow", - "branch": "flow" - } - ], - "recently_closed": [], - "statistics": { - "active_count": 1, - "total_closed": 0, - "recently_closed_included": 0 - } - } - }, - "global_statistics": { - "total_active": 1, - "total_closed": 0, - "branches_reporting": 1 - }, - "active_plans": [ - { - "plan_id": "FPLAN-0002", - "subject": "", - "status": "open", - "created": "2026-03-06T20:20:39.986512+00:00", - "file_path": "/home/coder/workspace/src/aipass/flow/FPLAN-0002_2026-03-06.md", - "relative_path": "flow", - "branch": "flow" - } - ], - "recently_closed": [], - "statistics": { - "active_count": 1, - "total_closed": 0, - "recently_closed_included": 0 - } -} \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 9dc26551..ee6297cc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -20,18 +20,11 @@ RUN python3 -m venv /opt/venv \ && chown -R 1000:1000 /opt/venv ENV PATH="/opt/venv/bin:$PATH" -# Startup script in /etc so it's NOT shadowed by /home/coder bind mount -RUN mkdir -p /etc/entrypoint.d -COPY setup-workspace.sh /etc/entrypoint.d/setup-workspace.sh -RUN chmod +x /etc/entrypoint.d/setup-workspace.sh - -# Override ENTRYPOINTD to our non-shadowed location -ENV ENTRYPOINTD=/etc/entrypoint.d +# Empty workspace — clone your own repo after boot +RUN mkdir -p /home/coder/workspace && chown 1000:1000 /home/coder/workspace USER 1000 ENV PATH="/opt/venv/bin:$PATH" EXPOSE 8080 -# Use the official entrypoint (already in the base image at /usr/bin/entrypoint.sh) -# It runs fixuid -> entrypoint.d scripts -> dumb-init code-server -ENTRYPOINT ["/usr/bin/entrypoint.sh", "--bind-addr", "0.0.0.0:8080", "--auth", "none", "/home/coder/workspace/AIPass"] +ENTRYPOINT ["/usr/bin/entrypoint.sh", "--bind-addr", "0.0.0.0:8080", "--auth", "none", "/home/coder/workspace"] diff --git a/README.md b/README.md index 49acc9d7..fa216772 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,7 @@ +[![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue)](pyproject.toml) +[![License: MIT](https://img.shields.io/badge/license-MIT-green)](LICENSE) +[![CI](https://github.com/AIOSAI/AIPass/actions/workflows/ci.yml/badge.svg)](https://github.com/AIOSAI/AIPass/actions/workflows/ci.yml) + # AIPass > **Building in public.** This is an active development repo — not a finished product. Modules are being built, tested, and rewired in real time. Some things work, some things don't yet. Follow along, poke around, or fork it and experiment. Contributions welcome once we stabilize. diff --git a/pyproject.toml b/pyproject.toml index c089263a..93762cc8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -44,6 +44,7 @@ dev = [ "pytest", "pytest-cov", "ruff", + "coverage", ] [project.scripts] @@ -54,7 +55,21 @@ seedgo = "aipass.seedgo.apps.seedgo:main" packages = ["src/aipass"] [tool.pytest.ini_options] -testpaths = ["tests"] +testpaths = ["tests", "src"] +norecursedirs = ["templates", "*.egg-info", ".git", ".venv", "__pycache__"] + +[tool.coverage.run] +source = ["src/aipass"] +omit = ["*/tests/*", "*/templates/*"] + +[tool.coverage.report] +show_missing = true +fail_under = 70 +exclude_lines = [ + "pragma: no cover", + "if __name__ == .__main__.", + "if TYPE_CHECKING:", +] [tool.ruff] line-length = 120 diff --git a/src/aipass/ai_mail/.aipass/aipass_local_prompt.md b/src/aipass/ai_mail/.aipass/aipass_local_prompt.md new file mode 100644 index 00000000..5b8bb896 --- /dev/null +++ b/src/aipass/ai_mail/.aipass/aipass_local_prompt.md @@ -0,0 +1,14 @@ +# AI_MAIL Branch-Local Context + + +> 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 diff --git a/src/aipass/ai_mail/.seed/bypass.json b/src/aipass/ai_mail/.seed/bypass.json deleted file mode 100644 index 6baed8ad..00000000 --- a/src/aipass/ai_mail/.seed/bypass.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "metadata": { - "version": "1.0.0", - "created": "2026-03-06T14:27:27.887566", - "description": "Standards bypass configuration for this branch" - }, - "bypass": [], - "notes": { - "usage": "Add entries to 'bypass' list to exclude specific violations", - "example": { - "file": "apps/modules/logger.py", - "standard": "cli", - "lines": [ - 146, - 177 - ], - "pattern": "if __name__ == '__main__'", - "reason": "Circular dependency - logger cannot import CLI" - }, - "fields": { - "file": "Relative path from branch root (required)", - "standard": "Standard name: cli, imports, naming, etc. (required)", - "lines": "Optional - specific line numbers to bypass", - "pattern": "Optional - pattern to match (e.g. 'if __name__')", - "reason": "Required - why this bypass exists" - } - } -} \ No newline at end of file diff --git a/src/aipass/api/.aipass/aipass_local_prompt.md b/src/aipass/api/.aipass/aipass_local_prompt.md new file mode 100644 index 00000000..01423f6b --- /dev/null +++ b/src/aipass/api/.aipass/aipass_local_prompt.md @@ -0,0 +1,14 @@ +# API Branch-Local Context + + +> 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 diff --git a/src/aipass/api/.seed/bypass.json b/src/aipass/api/.seed/bypass.json deleted file mode 100644 index d2d15ce2..00000000 --- a/src/aipass/api/.seed/bypass.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "metadata": { - "version": "1.0.0", - "created": "2026-03-06T14:27:31.471013", - "description": "Standards bypass configuration for this branch" - }, - "bypass": [], - "notes": { - "usage": "Add entries to 'bypass' list to exclude specific violations", - "example": { - "file": "apps/modules/logger.py", - "standard": "cli", - "lines": [ - 146, - 177 - ], - "pattern": "if __name__ == '__main__'", - "reason": "Circular dependency - logger cannot import CLI" - }, - "fields": { - "file": "Relative path from branch root (required)", - "standard": "Standard name: cli, imports, naming, etc. (required)", - "lines": "Optional - specific line numbers to bypass", - "pattern": "Optional - pattern to match (e.g. 'if __name__')", - "reason": "Required - why this bypass exists" - } - } -} \ No newline at end of file diff --git a/src/aipass/api/api_json/api_config.json b/src/aipass/api/api_json/api_config.json deleted file mode 100644 index fbf5686d..00000000 --- a/src/aipass/api/api_json/api_config.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "module_name": "api", - "version": "1.0.0", - "timestamp": "2025-11-13", - "config": { - "auto_save": true, - "enabled": true - } -} \ No newline at end of file diff --git a/src/aipass/api/api_json/api_data.json b/src/aipass/api/api_json/api_data.json deleted file mode 100644 index 32dac852..00000000 --- a/src/aipass/api/api_json/api_data.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "module_name": "api", - "created": "2025-11-13", - "last_updated": "2025-11-13", - "operations_total": 0, - "operations_successful": 0, - "operations_failed": 0 -} \ No newline at end of file diff --git a/src/aipass/api/api_json/api_key_config.json b/src/aipass/api/api_json/api_key_config.json deleted file mode 100644 index 961ba59b..00000000 --- a/src/aipass/api/api_json/api_key_config.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "module_name": "api_key", - "version": "1.0.0", - "timestamp": "2025-11-13", - "config": { - "auto_save": true, - "enabled": true - } -} \ No newline at end of file diff --git a/src/aipass/api/api_json/api_key_data.json b/src/aipass/api/api_json/api_key_data.json deleted file mode 100644 index b0741597..00000000 --- a/src/aipass/api/api_json/api_key_data.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "module_name": "api_key", - "created": "2025-11-13", - "last_updated": "2025-11-13", - "operations_total": 0, - "operations_successful": 0, - "operations_failed": 0 -} \ No newline at end of file diff --git a/src/aipass/api/api_json/api_key_log.json b/src/aipass/api/api_json/api_key_log.json deleted file mode 100644 index 64239f97..00000000 --- a/src/aipass/api/api_json/api_key_log.json +++ /dev/null @@ -1,16 +0,0 @@ -[ - { - "timestamp": "2026-03-06T19:26:31.512349", - "operation": "api_key_get-key", - "data": { - "command": "get-key" - } - }, - { - "timestamp": "2026-03-06T19:26:38.756413", - "operation": "api_key_validate", - "data": { - "command": "validate" - } - } -] \ No newline at end of file diff --git a/src/aipass/api/api_json/api_log.json b/src/aipass/api/api_json/api_log.json deleted file mode 100644 index 53ebbe84..00000000 --- a/src/aipass/api/api_json/api_log.json +++ /dev/null @@ -1,55 +0,0 @@ -[ - { - "timestamp": "2026-03-06T19:25:27.817286", - "operation": "api_help_displayed", - "data": { - "trigger": "--help" - } - }, - { - "timestamp": "2026-03-06T19:25:57.579810", - "operation": "api_command_attempted", - "data": { - "command": "test", - "modules_discovered": 4 - } - }, - { - "timestamp": "2026-03-06T19:26:31.498902", - "operation": "api_command_attempted", - "data": { - "command": "get-key", - "modules_discovered": 4 - } - }, - { - "timestamp": "2026-03-06T19:26:38.745089", - "operation": "api_command_attempted", - "data": { - "command": "validate", - "modules_discovered": 4 - } - }, - { - "timestamp": "2026-03-06T19:26:41.953458", - "operation": "api_command_attempted", - "data": { - "command": "stats", - "modules_discovered": 4 - } - }, - { - "timestamp": "2026-03-06T20:37:07.497952", - "operation": "api_help_displayed", - "data": { - "trigger": "--help" - } - }, - { - "timestamp": "2026-03-06T20:38:04.859299", - "operation": "api_help_displayed", - "data": { - "trigger": "--help" - } - } -] \ No newline at end of file diff --git a/src/aipass/api/api_json/usage_tracker_config.json b/src/aipass/api/api_json/usage_tracker_config.json deleted file mode 100644 index 522546d9..00000000 --- a/src/aipass/api/api_json/usage_tracker_config.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "module_name": "usage_tracker", - "version": "1.0.0", - "timestamp": "2025-11-13", - "config": { - "auto_save": true, - "enabled": true - } -} \ No newline at end of file diff --git a/src/aipass/api/api_json/usage_tracker_data.json b/src/aipass/api/api_json/usage_tracker_data.json deleted file mode 100644 index fb272849..00000000 --- a/src/aipass/api/api_json/usage_tracker_data.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "module_name": "usage_tracker", - "created": "2025-11-13", - "last_updated": "2025-11-13", - "operations_total": 0, - "operations_successful": 0, - "operations_failed": 0 -} \ No newline at end of file diff --git a/src/aipass/api/api_json/usage_tracker_log.json b/src/aipass/api/api_json/usage_tracker_log.json deleted file mode 100644 index 34f4255a..00000000 --- a/src/aipass/api/api_json/usage_tracker_log.json +++ /dev/null @@ -1,9 +0,0 @@ -[ - { - "timestamp": "2026-03-06T19:26:41.965942", - "operation": "usage_stats", - "data": { - "command": "stats" - } - } -] \ No newline at end of file diff --git a/src/aipass/cli/.aipass/aipass_local_prompt.md b/src/aipass/cli/.aipass/aipass_local_prompt.md new file mode 100644 index 00000000..2b7816da --- /dev/null +++ b/src/aipass/cli/.aipass/aipass_local_prompt.md @@ -0,0 +1,14 @@ +# CLI Branch-Local Context + + +> 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 diff --git a/src/aipass/cli/.seed/bypass.json b/src/aipass/cli/.seed/bypass.json deleted file mode 100644 index c565945b..00000000 --- a/src/aipass/cli/.seed/bypass.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "metadata": { - "version": "1.0.0", - "created": "2026-03-06T14:27:34.810230", - "description": "Standards bypass configuration for this branch" - }, - "bypass": [], - "notes": { - "usage": "Add entries to 'bypass' list to exclude specific violations", - "example": { - "file": "apps/modules/logger.py", - "standard": "cli", - "lines": [ - 146, - 177 - ], - "pattern": "if __name__ == '__main__'", - "reason": "Circular dependency - logger cannot import CLI" - }, - "fields": { - "file": "Relative path from branch root (required)", - "standard": "Standard name: cli, imports, naming, etc. (required)", - "lines": "Optional - specific line numbers to bypass", - "pattern": "Optional - pattern to match (e.g. 'if __name__')", - "reason": "Required - why this bypass exists" - } - } -} \ No newline at end of file diff --git a/src/aipass/devpulse/.aipass/aipass_local_prompt.md b/src/aipass/devpulse/.aipass/aipass_local_prompt.md new file mode 100644 index 00000000..4b5ca2eb --- /dev/null +++ b/src/aipass/devpulse/.aipass/aipass_local_prompt.md @@ -0,0 +1,61 @@ +# DEVPULSE Branch-Local Context + +You are DEVPULSE — the orchestration hub for the AIPass public repo. + +## What You Are + +You are to AIPass what DEV_CENTRAL is to Dev-Pass. You coordinate, plan, delegate, and track. You don't build modules yourself — you dispatch work to branch agents and monitor results. + +**Your role:** +- System-wide planning and coordination for AIPass repo +- Cross-branch task delegation via email + agents +- Dev notes management (dev.local.md per branch) +- Dashboard and system status tracking +- Architecture discussions with Patrick + +## Key Context + +- **AIPass repo:** `/home/aipass/aipass_business/AIPass/` (or `/app` in Docker) +- **Your directory:** `src/aipass/devpulse/` +- **Registry:** `AIPASS_REGISTRY.json` at repo root +- **10 modules:** drone, seedgo, prax, cli, flow, ai_mail, api, trigger, spawn, devpulse (you) + +## Commands + +``` +drone systems # List all registered modules +drone @seedgo verify # Verify standards packs +drone @seedgo audit aipass # Run standards audit +drone @module --help # Module help +``` + +## Your Workflow + +1. Check your memories (.trinity/local.json, observations.json) +2. Check system status (drone systems, seedgo verify) +3. Review what needs building (MPLAN-001 tracks all module status) +4. Dispatch work to branches or build directly if small +5. Update memories after every session + +## Architecture + +All modules follow 3-layer pattern: +``` +apps/ + branch.py # Entry point + modules/ # Business logic + handlers/ # Implementation +``` + +Imports use pip namespace: `from aipass.{module}.apps.modules...` + +## Critical Rules + +- Imports must use `from aipass.{module}...` — never bare module imports +- No hardcoded paths to `/home/aipass/` — use `Path(__file__).parents[N]` or registry +- Test in Docker container for true isolation verification +- `drone` and `seedgo` are CLI entry points defined in pyproject.toml + +## Current State + +Fresh spawn. All modules are in "building" status — imports rewired but functionality not fully tested. Docker container at localhost:8080 is your testing ground. diff --git a/src/aipass/devpulse/.aipass/branch_system_prompt.md b/src/aipass/devpulse/.aipass/branch_system_prompt.md new file mode 100644 index 00000000..4b5ca2eb --- /dev/null +++ b/src/aipass/devpulse/.aipass/branch_system_prompt.md @@ -0,0 +1,61 @@ +# DEVPULSE Branch-Local Context + +You are DEVPULSE — the orchestration hub for the AIPass public repo. + +## What You Are + +You are to AIPass what DEV_CENTRAL is to Dev-Pass. You coordinate, plan, delegate, and track. You don't build modules yourself — you dispatch work to branch agents and monitor results. + +**Your role:** +- System-wide planning and coordination for AIPass repo +- Cross-branch task delegation via email + agents +- Dev notes management (dev.local.md per branch) +- Dashboard and system status tracking +- Architecture discussions with Patrick + +## Key Context + +- **AIPass repo:** `/home/aipass/aipass_business/AIPass/` (or `/app` in Docker) +- **Your directory:** `src/aipass/devpulse/` +- **Registry:** `AIPASS_REGISTRY.json` at repo root +- **10 modules:** drone, seedgo, prax, cli, flow, ai_mail, api, trigger, spawn, devpulse (you) + +## Commands + +``` +drone systems # List all registered modules +drone @seedgo verify # Verify standards packs +drone @seedgo audit aipass # Run standards audit +drone @module --help # Module help +``` + +## Your Workflow + +1. Check your memories (.trinity/local.json, observations.json) +2. Check system status (drone systems, seedgo verify) +3. Review what needs building (MPLAN-001 tracks all module status) +4. Dispatch work to branches or build directly if small +5. Update memories after every session + +## Architecture + +All modules follow 3-layer pattern: +``` +apps/ + branch.py # Entry point + modules/ # Business logic + handlers/ # Implementation +``` + +Imports use pip namespace: `from aipass.{module}.apps.modules...` + +## Critical Rules + +- Imports must use `from aipass.{module}...` — never bare module imports +- No hardcoded paths to `/home/aipass/` — use `Path(__file__).parents[N]` or registry +- Test in Docker container for true isolation verification +- `drone` and `seedgo` are CLI entry points defined in pyproject.toml + +## Current State + +Fresh spawn. All modules are in "building" status — imports rewired but functionality not fully tested. Docker container at localhost:8080 is your testing ground. diff --git a/src/aipass/drone/.aipass/aipass_local_prompt.md b/src/aipass/drone/.aipass/aipass_local_prompt.md new file mode 100644 index 00000000..e4de3ebc --- /dev/null +++ b/src/aipass/drone/.aipass/aipass_local_prompt.md @@ -0,0 +1,14 @@ +# DRONE Branch-Local Context + + +> 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 diff --git a/src/aipass/drone/.seed/bypass.json b/src/aipass/drone/.seed/bypass.json deleted file mode 100644 index 7452d6be..00000000 --- a/src/aipass/drone/.seed/bypass.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "metadata": { - "version": "1.0.0", - "created": "2026-03-06T14:27:37.777414", - "description": "Standards bypass configuration for this branch" - }, - "bypass": [], - "notes": { - "usage": "Add entries to 'bypass' list to exclude specific violations", - "example": { - "file": "apps/modules/logger.py", - "standard": "cli", - "lines": [ - 146, - 177 - ], - "pattern": "if __name__ == '__main__'", - "reason": "Circular dependency - logger cannot import CLI" - }, - "fields": { - "file": "Relative path from branch root (required)", - "standard": "Standard name: cli, imports, naming, etc. (required)", - "lines": "Optional - specific line numbers to bypass", - "pattern": "Optional - pattern to match (e.g. 'if __name__')", - "reason": "Required - why this bypass exists" - } - } -} \ No newline at end of file diff --git a/src/aipass/flow/.aipass/aipass_local_prompt.md b/src/aipass/flow/.aipass/aipass_local_prompt.md new file mode 100644 index 00000000..5fad5a2b --- /dev/null +++ b/src/aipass/flow/.aipass/aipass_local_prompt.md @@ -0,0 +1,14 @@ +# FLOW Branch-Local Context + + +> 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 diff --git a/src/aipass/flow/.seed/bypass.json b/src/aipass/flow/.seed/bypass.json deleted file mode 100644 index d7fab058..00000000 --- a/src/aipass/flow/.seed/bypass.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "metadata": { - "version": "1.0.0", - "created": "2026-03-06T14:27:39.378089", - "description": "Standards bypass configuration for this branch" - }, - "bypass": [], - "notes": { - "usage": "Add entries to 'bypass' list to exclude specific violations", - "example": { - "file": "apps/modules/logger.py", - "standard": "cli", - "lines": [ - 146, - 177 - ], - "pattern": "if __name__ == '__main__'", - "reason": "Circular dependency - logger cannot import CLI" - }, - "fields": { - "file": "Relative path from branch root (required)", - "standard": "Standard name: cli, imports, naming, etc. (required)", - "lines": "Optional - specific line numbers to bypass", - "pattern": "Optional - pattern to match (e.g. 'if __name__')", - "reason": "Required - why this bypass exists" - } - } -} \ No newline at end of file diff --git a/src/aipass/flow/flow_json/close_plan_config.json b/src/aipass/flow/flow_json/close_plan_config.json deleted file mode 100644 index 385cdcf4..00000000 --- a/src/aipass/flow/flow_json/close_plan_config.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "module_name": "close_plan", - "version": "1.0.0", - "timestamp": "2025-11-13", - "config": { - "auto_save": true, - "enabled": true - } -} \ No newline at end of file diff --git a/src/aipass/flow/flow_json/close_plan_data.json b/src/aipass/flow/flow_json/close_plan_data.json deleted file mode 100644 index dff019bd..00000000 --- a/src/aipass/flow/flow_json/close_plan_data.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "module_name": "close_plan", - "created": "2025-11-13", - "last_updated": "2025-11-13", - "operations_total": 0, - "operations_successful": 0, - "operations_failed": 0 -} \ No newline at end of file diff --git a/src/aipass/flow/flow_json/close_plan_log.json b/src/aipass/flow/flow_json/close_plan_log.json deleted file mode 100644 index d512b01a..00000000 --- a/src/aipass/flow/flow_json/close_plan_log.json +++ /dev/null @@ -1,23 +0,0 @@ -[ - { - "timestamp": "2026-03-06T19:26:52.582808", - "operation": "plan_closed", - "data": { - "command": "close", - "args": [ - "FPLAN-0001", - "--yes" - ] - } - }, - { - "timestamp": "2026-03-06T20:21:02.790344", - "operation": "plan_closed", - "data": { - "command": "close", - "args": [ - "0002" - ] - } - } -] \ No newline at end of file diff --git a/src/aipass/flow/flow_json/create_plan_config.json b/src/aipass/flow/flow_json/create_plan_config.json deleted file mode 100644 index f6fd0426..00000000 --- a/src/aipass/flow/flow_json/create_plan_config.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "module_name": "create_plan", - "version": "1.0.0", - "timestamp": "2025-11-13", - "config": { - "auto_save": true, - "enabled": true - } -} \ No newline at end of file diff --git a/src/aipass/flow/flow_json/create_plan_data.json b/src/aipass/flow/flow_json/create_plan_data.json deleted file mode 100644 index 365b7e3f..00000000 --- a/src/aipass/flow/flow_json/create_plan_data.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "module_name": "create_plan", - "created": "2025-11-13", - "last_updated": "2025-11-13", - "operations_total": 0, - "operations_successful": 0, - "operations_failed": 0 -} \ No newline at end of file diff --git a/src/aipass/flow/flow_json/create_plan_log.json b/src/aipass/flow/flow_json/create_plan_log.json deleted file mode 100644 index 6d7bb244..00000000 --- a/src/aipass/flow/flow_json/create_plan_log.json +++ /dev/null @@ -1,21 +0,0 @@ -[ - { - "timestamp": "2026-03-06T19:26:45.708820", - "operation": "plan_created", - "data": { - "command": "create", - "args": [ - "/tmp", - "Test plan from devpulse" - ] - } - }, - { - "timestamp": "2026-03-06T20:20:39.984820", - "operation": "plan_created", - "data": { - "command": "create", - "args": [] - } - } -] \ No newline at end of file diff --git a/src/aipass/flow/flow_json/flow_registry.json b/src/aipass/flow/flow_json/flow_registry.json deleted file mode 100644 index d07cd2d1..00000000 --- a/src/aipass/flow/flow_json/flow_registry.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "plans": {}, - "next_number": 3, - "last_updated": "2026-03-06T20:21:02.795560+00:00" -} \ No newline at end of file diff --git a/src/aipass/flow/flow_json/list_plans_config.json b/src/aipass/flow/flow_json/list_plans_config.json deleted file mode 100644 index 8392dbc7..00000000 --- a/src/aipass/flow/flow_json/list_plans_config.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "module_name": "list_plans", - "version": "1.0.0", - "timestamp": "2025-11-13", - "config": { - "auto_save": true, - "enabled": true - } -} \ No newline at end of file diff --git a/src/aipass/flow/flow_json/list_plans_data.json b/src/aipass/flow/flow_json/list_plans_data.json deleted file mode 100644 index 6eb3017f..00000000 --- a/src/aipass/flow/flow_json/list_plans_data.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "module_name": "list_plans", - "created": "2025-11-13", - "last_updated": "2025-11-13", - "operations_total": 0, - "operations_successful": 0, - "operations_failed": 0 -} \ No newline at end of file diff --git a/src/aipass/flow/flow_json/list_plans_log.json b/src/aipass/flow/flow_json/list_plans_log.json deleted file mode 100644 index 5515a66f..00000000 --- a/src/aipass/flow/flow_json/list_plans_log.json +++ /dev/null @@ -1,18 +0,0 @@ -[ - { - "timestamp": "2026-03-06T19:25:53.833365", - "operation": "plans_listed", - "data": { - "command": "list", - "args": [] - } - }, - { - "timestamp": "2026-03-06T19:26:49.120795", - "operation": "plans_listed", - "data": { - "command": "list", - "args": [] - } - } -] \ No newline at end of file diff --git a/src/aipass/prax/.aipass/aipass_local_prompt.md b/src/aipass/prax/.aipass/aipass_local_prompt.md new file mode 100644 index 00000000..e5fbb0e8 --- /dev/null +++ b/src/aipass/prax/.aipass/aipass_local_prompt.md @@ -0,0 +1,14 @@ +# PRAX Branch-Local Context + + +> 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 diff --git a/src/aipass/prax/.seed/bypass.json b/src/aipass/prax/.seed/bypass.json deleted file mode 100644 index 6de4af5a..00000000 --- a/src/aipass/prax/.seed/bypass.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "metadata": { - "version": "1.0.0", - "created": "2026-03-06T14:27:42.646499", - "description": "Standards bypass configuration for this branch" - }, - "bypass": [], - "notes": { - "usage": "Add entries to 'bypass' list to exclude specific violations", - "example": { - "file": "apps/modules/logger.py", - "standard": "cli", - "lines": [ - 146, - 177 - ], - "pattern": "if __name__ == '__main__'", - "reason": "Circular dependency - logger cannot import CLI" - }, - "fields": { - "file": "Relative path from branch root (required)", - "standard": "Standard name: cli, imports, naming, etc. (required)", - "lines": "Optional - specific line numbers to bypass", - "pattern": "Optional - pattern to match (e.g. 'if __name__')", - "reason": "Required - why this bypass exists" - } - } -} \ No newline at end of file diff --git a/src/aipass/seedgo/.aipass/aipass_local_prompt.md b/src/aipass/seedgo/.aipass/aipass_local_prompt.md new file mode 100644 index 00000000..752a5084 --- /dev/null +++ b/src/aipass/seedgo/.aipass/aipass_local_prompt.md @@ -0,0 +1,14 @@ +# SEEDGO Branch-Local Context + + +> 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 diff --git a/src/aipass/seedgo/.seed/bypass.json b/src/aipass/seedgo/.seed/bypass.json deleted file mode 100644 index 966e843f..00000000 --- a/src/aipass/seedgo/.seed/bypass.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "metadata": { - "version": "1.0.0", - "created": "2026-03-06T14:27:46.561948", - "description": "Standards bypass configuration for this branch" - }, - "bypass": [], - "notes": { - "usage": "Add entries to 'bypass' list to exclude specific violations", - "example": { - "file": "apps/modules/logger.py", - "standard": "cli", - "lines": [ - 146, - 177 - ], - "pattern": "if __name__ == '__main__'", - "reason": "Circular dependency - logger cannot import CLI" - }, - "fields": { - "file": "Relative path from branch root (required)", - "standard": "Standard name: cli, imports, naming, etc. (required)", - "lines": "Optional - specific line numbers to bypass", - "pattern": "Optional - pattern to match (e.g. 'if __name__')", - "reason": "Required - why this bypass exists" - } - } -} \ No newline at end of file diff --git a/src/aipass/trigger/.aipass/aipass_local_prompt.md b/src/aipass/trigger/.aipass/aipass_local_prompt.md new file mode 100644 index 00000000..655d9f3d --- /dev/null +++ b/src/aipass/trigger/.aipass/aipass_local_prompt.md @@ -0,0 +1,14 @@ +# TRIGGER Branch-Local Context + + +> 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 diff --git a/src/aipass/trigger/.seed/bypass.json b/src/aipass/trigger/.seed/bypass.json deleted file mode 100644 index da201288..00000000 --- a/src/aipass/trigger/.seed/bypass.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "metadata": { - "version": "1.0.0", - "created": "2026-03-06T14:27:53.459073", - "description": "Standards bypass configuration for this branch" - }, - "bypass": [], - "notes": { - "usage": "Add entries to 'bypass' list to exclude specific violations", - "example": { - "file": "apps/modules/logger.py", - "standard": "cli", - "lines": [ - 146, - 177 - ], - "pattern": "if __name__ == '__main__'", - "reason": "Circular dependency - logger cannot import CLI" - }, - "fields": { - "file": "Relative path from branch root (required)", - "standard": "Standard name: cli, imports, naming, etc. (required)", - "lines": "Optional - specific line numbers to bypass", - "pattern": "Optional - pattern to match (e.g. 'if __name__')", - "reason": "Required - why this bypass exists" - } - } -} \ No newline at end of file diff --git a/src/aipass/trigger/trigger_json/trigger_data.json b/src/aipass/trigger/trigger_json/trigger_data.json deleted file mode 100644 index 37ecdbbf..00000000 --- a/src/aipass/trigger/trigger_json/trigger_data.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "error_catchup": { - "last_scan_timestamp": "2026-03-06T14:27:27.869613", - "processed_hashes": [ - "ace01637", - "69de737b", - "c7edc03b", - "4095ef97", - "68dd0ab6", - "541e0b9b", - "02d93909" - ], - "max_hashes": 500, - "max_lookback_hours": 24 - } -} \ No newline at end of file diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 00000000..e69de29b