feat(AIPASS): Fix aipass init: stop creating memo.md in project scaffolds
Co-Authored-By: @AIPASS <AIPASS@aipass>
This commit is contained in:
@@ -1,23 +0,0 @@
|
||||
# Memory Update
|
||||
|
||||
Purpose: Update branch memory files after completing work this session.
|
||||
|
||||
## Execution
|
||||
|
||||
1. Read `.trinity/passport.json` first — re-absorb your identity, role, and principles before writing memories
|
||||
2. Review what was done this session (context, recent changes, key decisions)
|
||||
3. Update each file below as needed
|
||||
4. Confirm completion — list files updated
|
||||
|
||||
## Memory Roles
|
||||
|
||||
Each memory file plays a distinct role. Update based on what actually changed this session.
|
||||
|
||||
- **`.trinity/passport.json`** — IDENTITY. Who you are: role, capabilities, principles. Only update if identity genuinely evolved this session. Don't touch it just to touch it.
|
||||
- **`.trinity/local.json`** — YOUR MEMORY. Session history and key_learnings. Add a session entry for significant work. Add key_learnings for facts you'd need next time. Trim oldest sessions if over 20.
|
||||
- **`.trinity/observations.json`** — YOUR MEMORY OF THE USER. Collaboration insights, preferences, friction points, flow states. Skip entirely if nothing new about the user this session.
|
||||
- **`STATUS.local.md`** — PUBLIC STATUS BEACON. Current work, known issues, todos, notepad. Auto-synced to central STATUS.md on PR events — this is how other branches see you. Keep Current Work accurate and drop quick notes in the Notepad section.
|
||||
|
||||
## If Relevant
|
||||
|
||||
- **README.md** — Does it reflect current state? Update if stale.
|
||||
@@ -1,57 +0,0 @@
|
||||
# Session Wrap-Up
|
||||
|
||||
Purpose: Button up everything at the end of a session — or before a /compact. Memories, plans, git — all tidy. Works for both closing out a chat and preparing for compaction.
|
||||
|
||||
**Workflow:** `/prep` → review output → close chat or `/compact`
|
||||
|
||||
## Execution
|
||||
|
||||
1. Read `.trinity/passport.json` first — re-absorb your identity before writing anything
|
||||
2. Do ALL of the following, then confirm what was updated
|
||||
|
||||
## 1. Memories
|
||||
|
||||
Each memory file plays a distinct role. Update based on what actually changed this session.
|
||||
|
||||
- **`.trinity/passport.json`** — IDENTITY. Who you are: role, capabilities, principles. Only update if identity genuinely evolved this session.
|
||||
- **`.trinity/local.json`** — YOUR MEMORY. Add/update session entry with a summary of work done. Add key_learnings for anything learned. Trim oldest sessions if over 20.
|
||||
- **`.trinity/observations.json`** — YOUR MEMORY OF THE USER. Collaboration insights, preferences, friction points. Skip if nothing new about the user this session.
|
||||
- **`STATUS.local.md`** — PUBLIC STATUS BEACON. Current work, known issues, todos, notepad. Auto-synced to central STATUS.md on PR events — this is how other branches see you. Keep Current Work accurate.
|
||||
|
||||
## 2. Active Plans
|
||||
|
||||
- Check any DPLANs or FPLANs referenced in this session
|
||||
- Update their execution logs, status, decision logs with current state
|
||||
- If a plan was completed, note it (but don't close — the user does that)
|
||||
|
||||
## 3. Git State
|
||||
|
||||
- Run `git status` — report uncommitted changes
|
||||
- If there's a logical commit waiting, suggest it (don't commit without asking)
|
||||
- Note the current branch and any open PRs
|
||||
|
||||
## 4. Inbox
|
||||
|
||||
- Run `drone @ai_mail inbox 2>/dev/null` — report any unread emails
|
||||
- Close any that were already processed but not formally closed
|
||||
|
||||
## 5. Loose Ends
|
||||
|
||||
- Flag anything in-flight: running background agents, dispatched branches waiting for replies, pending decisions
|
||||
- If anything can't survive compaction (e.g., agent IDs needed for resume), write it to STATUS.local.md Notepad
|
||||
|
||||
## Confirm
|
||||
|
||||
List everything updated. Format:
|
||||
```
|
||||
Prep complete:
|
||||
- local.json: [what was added]
|
||||
- observations.json: [updated / skipped]
|
||||
- STATUS.local.md: [updated / skipped]
|
||||
- Plans: [which ones updated]
|
||||
- Git: [branch, uncommitted count, suggestion]
|
||||
- Inbox: [count, action taken]
|
||||
- Loose ends: [any flagged]
|
||||
|
||||
Ready to close out or /compact.
|
||||
```
|
||||
@@ -1,4 +1,42 @@
|
||||
{
|
||||
"hooks": {
|
||||
"UserPromptSubmit": [
|
||||
{
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "python3 .claude/hooks/branch_prompt_loader.py"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "python3 .claude/hooks/email_notification.py"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "python3 .claude/hooks/identity_injector.py"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"PreCompact": [
|
||||
{
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "python3 .claude/hooks/pre_compact.py"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"env": {
|
||||
"AIPASS_HOME": "/home/patrick/Projects/AIPass"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"branch": "AIPASS",
|
||||
"feature_branch": "",
|
||||
"started": "2026-05-08T02:08:34.233967+00:00",
|
||||
"pid": 380867
|
||||
}
|
||||
@@ -319,6 +319,7 @@ def init_project(target: Path, project_name: str | None = None) -> dict:
|
||||
created.append(str(settings_path))
|
||||
|
||||
# 9b. .claude/commands/prep.md — /prep session wrap-up slash command
|
||||
# Only prep.md here — memo.md belongs at provider level (~/.claude/commands/)
|
||||
commands_dir = claude_dir / "commands"
|
||||
commands_dir.mkdir(exist_ok=True)
|
||||
prep_path = commands_dir / "prep.md"
|
||||
@@ -326,12 +327,6 @@ def init_project(target: Path, project_name: str | None = None) -> dict:
|
||||
prep_path.write_text(sc.prep_md(), encoding="utf-8")
|
||||
created.append(str(prep_path))
|
||||
|
||||
# 9c. .claude/commands/memo.md — /memo memory update slash command
|
||||
memo_path = commands_dir / "memo.md"
|
||||
if not memo_path.exists():
|
||||
memo_path.write_text(sc.memo_md(), encoding="utf-8")
|
||||
created.append(str(memo_path))
|
||||
|
||||
# 9d. Ship enforcement + injector hooks from AIPass install
|
||||
if aipass_home:
|
||||
shipped = _ship_hooks(aipass_home, target)
|
||||
@@ -465,6 +460,7 @@ def update_project(target: Path) -> dict:
|
||||
already_current.append(str(gemini_md_path))
|
||||
|
||||
# .claude/commands/prep.md — managed slash command, refresh to latest
|
||||
# Only prep.md — memo.md belongs at provider level (~/.claude/commands/)
|
||||
commands_dir = claude_dir / "commands"
|
||||
commands_dir.mkdir(exist_ok=True)
|
||||
prep_path = commands_dir / "prep.md"
|
||||
@@ -475,15 +471,6 @@ def update_project(target: Path) -> dict:
|
||||
else:
|
||||
already_current.append(str(prep_path))
|
||||
|
||||
# .claude/commands/memo.md — managed slash command, refresh to latest
|
||||
memo_path = commands_dir / "memo.md"
|
||||
generated = sc.memo_md()
|
||||
if not memo_path.exists() or memo_path.read_text(encoding="utf-8") != generated:
|
||||
memo_path.write_text(generated, encoding="utf-8")
|
||||
updated.append(str(memo_path))
|
||||
else:
|
||||
already_current.append(str(memo_path))
|
||||
|
||||
# Re-sync enforcement + injector hooks from AIPass install
|
||||
hook_home = aipass_home or _detect_aipass_home()
|
||||
if hook_home:
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
# Memory Update
|
||||
|
||||
Purpose: Update branch memory files after completing work this session.
|
||||
|
||||
## Execution
|
||||
|
||||
1. Read `.trinity/passport.json` first — re-absorb your identity, role, and principles before writing memories
|
||||
2. Review what was done this session (context, recent changes, key decisions)
|
||||
3. Update each file below as needed
|
||||
4. Confirm completion — list files updated
|
||||
|
||||
## Memory Roles
|
||||
|
||||
Each memory file plays a distinct role. Update based on what actually changed this session.
|
||||
|
||||
- **`.trinity/passport.json`** — IDENTITY. Who you are: role, capabilities, principles. Only update if identity genuinely evolved this session. Don't touch it just to touch it.
|
||||
- **`.trinity/local.json`** — YOUR MEMORY. Session history and key_learnings. Add a session entry for significant work. Add key_learnings for facts you'd need next time. Trim oldest sessions if over 20.
|
||||
- **`.trinity/observations.json`** — YOUR MEMORY OF THE USER. Collaboration insights, preferences, friction points, flow states. Skip entirely if nothing new about the user this session.
|
||||
- **`STATUS.local.md`** — PUBLIC STATUS BEACON. Current work, known issues, todos, notepad. Auto-synced to central STATUS.md on PR events — this is how other branches see you. Keep Current Work accurate and drop quick notes in the Notepad section.
|
||||
|
||||
## If Relevant
|
||||
|
||||
- **README.md** — Does it reflect current state? Update if stale.
|
||||
@@ -1,57 +0,0 @@
|
||||
# Session Wrap-Up
|
||||
|
||||
Purpose: Button up everything at the end of a session — or before a /compact. Memories, plans, git — all tidy. Works for both closing out a chat and preparing for compaction.
|
||||
|
||||
**Workflow:** `/prep` → review output → close chat or `/compact`
|
||||
|
||||
## Execution
|
||||
|
||||
1. Read `.trinity/passport.json` first — re-absorb your identity before writing anything
|
||||
2. Do ALL of the following, then confirm what was updated
|
||||
|
||||
## 1. Memories
|
||||
|
||||
Each memory file plays a distinct role. Update based on what actually changed this session.
|
||||
|
||||
- **`.trinity/passport.json`** — IDENTITY. Who you are: role, capabilities, principles. Only update if identity genuinely evolved this session.
|
||||
- **`.trinity/local.json`** — YOUR MEMORY. Add/update session entry with a summary of work done. Add key_learnings for anything learned. Trim oldest sessions if over 20.
|
||||
- **`.trinity/observations.json`** — YOUR MEMORY OF THE USER. Collaboration insights, preferences, friction points. Skip if nothing new about the user this session.
|
||||
- **`STATUS.local.md`** — PUBLIC STATUS BEACON. Current work, known issues, todos, notepad. Auto-synced to central STATUS.md on PR events — this is how other branches see you. Keep Current Work accurate.
|
||||
|
||||
## 2. Active Plans
|
||||
|
||||
- Check any DPLANs or FPLANs referenced in this session
|
||||
- Update their execution logs, status, decision logs with current state
|
||||
- If a plan was completed, note it (but don't close — the user does that)
|
||||
|
||||
## 3. Git State
|
||||
|
||||
- Run `git status` — report uncommitted changes
|
||||
- If there's a logical commit waiting, suggest it (don't commit without asking)
|
||||
- Note the current branch and any open PRs
|
||||
|
||||
## 4. Inbox
|
||||
|
||||
- Run `drone @ai_mail inbox 2>/dev/null` — report any unread emails
|
||||
- Close any that were already processed but not formally closed
|
||||
|
||||
## 5. Loose Ends
|
||||
|
||||
- Flag anything in-flight: running background agents, dispatched branches waiting for replies, pending decisions
|
||||
- If anything can't survive compaction (e.g., agent IDs needed for resume), write it to STATUS.local.md Notepad
|
||||
|
||||
## Confirm
|
||||
|
||||
List everything updated. Format:
|
||||
```
|
||||
Prep complete:
|
||||
- local.json: [what was added]
|
||||
- observations.json: [updated / skipped]
|
||||
- STATUS.local.md: [updated / skipped]
|
||||
- Plans: [which ones updated]
|
||||
- Git: [branch, uncommitted count, suggestion]
|
||||
- Inbox: [count, action taken]
|
||||
- Loose ends: [any flagged]
|
||||
|
||||
Ready to close out or /compact.
|
||||
```
|
||||
@@ -1,4 +1,42 @@
|
||||
{
|
||||
"hooks": {
|
||||
"UserPromptSubmit": [
|
||||
{
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "python3 .claude/hooks/branch_prompt_loader.py"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "python3 .claude/hooks/email_notification.py"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "python3 .claude/hooks/identity_injector.py"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"PreCompact": [
|
||||
{
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "python3 .claude/hooks/pre_compact.py"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"env": {
|
||||
"AIPASS_HOME": "/home/patrick/Projects/AIPass"
|
||||
}
|
||||
|
||||
@@ -104,7 +104,6 @@ def test_init_project_creates_all_expected_files(tmp_path):
|
||||
target / ".gitignore",
|
||||
target / ".claude" / "settings.json",
|
||||
target / ".claude" / "commands" / "prep.md",
|
||||
target / ".claude" / "commands" / "memo.md",
|
||||
target / ".ai_mail.local" / "inbox.json",
|
||||
]
|
||||
for f in expected_files:
|
||||
@@ -119,8 +118,8 @@ def test_init_project_creates_all_expected_files(tmp_path):
|
||||
# No local prompt at project level (belongs in agent dirs only)
|
||||
assert not (target / ".aipass" / "aipass_local_prompt.md").exists()
|
||||
|
||||
# 11 items + 2 commands + 7 shipped hooks (when AIPASS_HOME detected) = 20
|
||||
assert len(result["created_files"]) == 20
|
||||
# 11 items + 1 command (prep.md) + 7 shipped hooks (when AIPASS_HOME detected) = 19
|
||||
assert len(result["created_files"]) == 19
|
||||
|
||||
|
||||
def test_init_project_return_dict_structure(tmp_path):
|
||||
@@ -354,7 +353,7 @@ def test_init_project_auto_creates_target_dir(tmp_path):
|
||||
|
||||
assert target.is_dir()
|
||||
assert result["project_name"] == "NESTED"
|
||||
assert len(result["created_files"]) == 20
|
||||
assert len(result["created_files"]) == 19
|
||||
|
||||
|
||||
def test_init_project_defaults_name_from_directory(tmp_path):
|
||||
@@ -410,8 +409,8 @@ def test_init_project_skips_existing_optional_files(tmp_path):
|
||||
|
||||
result = init_project(target, project_name="eta")
|
||||
|
||||
# Registry + prep.md + memo.md + 7 shipped hooks = 10 (everything else pre-existed)
|
||||
assert len(result["created_files"]) == 10
|
||||
# Registry + prep.md + 7 shipped hooks = 9 (everything else pre-existed)
|
||||
assert len(result["created_files"]) == 9
|
||||
|
||||
# Verify pre-existing files were NOT overwritten
|
||||
md_content = (target / "CLAUDE.md").read_text(encoding="utf-8")
|
||||
@@ -504,7 +503,7 @@ def test_update_project_already_current_after_init(tmp_path):
|
||||
result = update_project(target)
|
||||
|
||||
assert len(result["updated_files"]) == 0
|
||||
assert len(result["already_current"]) == 7
|
||||
assert len(result["already_current"]) == 6
|
||||
|
||||
|
||||
def test_update_project_idempotent(tmp_path):
|
||||
@@ -583,8 +582,8 @@ def test_update_project_creates_missing_managed_dirs(tmp_path):
|
||||
|
||||
assert (target / ".aipass" / "aipass_global_prompt.md").exists()
|
||||
assert (target / ".claude" / "settings.json").exists()
|
||||
# Managed files in deleted dirs re-written (global_prompt, settings, prep, memo + 7 hooks)
|
||||
assert len(result["updated_files"]) == 11
|
||||
# Managed files in deleted dirs re-written (global_prompt, settings, prep + 7 hooks)
|
||||
assert len(result["updated_files"]) == 10
|
||||
assert len(result["already_current"]) == 3
|
||||
|
||||
|
||||
@@ -741,61 +740,15 @@ def test_update_project_adds_aipass_home_if_missing(tmp_path):
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def test_init_project_creates_memo_md(tmp_path):
|
||||
"""init_project creates .claude/commands/memo.md slash command."""
|
||||
def test_init_project_no_memo_md(tmp_path):
|
||||
"""init_project does NOT create memo.md — it belongs at provider level."""
|
||||
target = tmp_path / "proj"
|
||||
target.mkdir()
|
||||
|
||||
init_project(target, project_name="memo")
|
||||
|
||||
memo_path = target / ".claude" / "commands" / "memo.md"
|
||||
assert memo_path.exists()
|
||||
content = memo_path.read_text(encoding="utf-8")
|
||||
assert "# Memory Update" in content
|
||||
assert ".trinity/passport.json" in content
|
||||
assert ".trinity/local.json" in content
|
||||
assert "STATUS.local.md" in content
|
||||
|
||||
|
||||
def test_init_project_memo_not_overwritten_on_rerun(tmp_path):
|
||||
"""Re-running init skips existing memo.md."""
|
||||
target = tmp_path / "proj"
|
||||
target.mkdir()
|
||||
init_project(target, project_name="memo")
|
||||
|
||||
memo_path = target / ".claude" / "commands" / "memo.md"
|
||||
memo_path.write_text("# Custom memo\n", encoding="utf-8")
|
||||
|
||||
init_project(target, project_name="memo")
|
||||
|
||||
assert memo_path.read_text(encoding="utf-8") == "# Custom memo\n"
|
||||
|
||||
|
||||
def test_update_project_refreshes_memo_md(tmp_path):
|
||||
"""update_project refreshes memo.md when content differs."""
|
||||
target = tmp_path / "proj"
|
||||
target.mkdir()
|
||||
init_project(target, project_name="umemo")
|
||||
|
||||
memo_path = target / ".claude" / "commands" / "memo.md"
|
||||
memo_path.write_text("# Stale content\n", encoding="utf-8")
|
||||
|
||||
result = update_project(target)
|
||||
|
||||
assert str(memo_path) in result["updated_files"]
|
||||
assert "# Memory Update" in memo_path.read_text(encoding="utf-8")
|
||||
|
||||
|
||||
def test_update_project_memo_already_current(tmp_path):
|
||||
"""update_project reports memo.md as already_current when unchanged."""
|
||||
target = tmp_path / "proj"
|
||||
target.mkdir()
|
||||
init_project(target, project_name="memocur")
|
||||
|
||||
result = update_project(target)
|
||||
|
||||
memo_path = target / ".claude" / "commands" / "memo.md"
|
||||
assert str(memo_path) in result["already_current"]
|
||||
assert not memo_path.exists()
|
||||
|
||||
|
||||
def test_init_project_ships_hooks(tmp_path):
|
||||
|
||||
Reference in New Issue
Block a user