Skip to content

Fix team cleanup deleting plans from other teams#6

Merged
tjb-tech merged 1 commit intoHKUDS:mainfrom
fancyboi999:fancy/fix-team-plan-storage
Mar 18, 2026
Merged

Fix team cleanup deleting plans from other teams#6
tjb-tech merged 1 commit intoHKUDS:mainfrom
fancyboi999:fancy/fix-team-plan-storage

Conversation

@fancyboi999
Copy link
Copy Markdown
Contributor

@fancyboi999 fancyboi999 commented Mar 18, 2026

Summary

  • store plan markdown under plans/<team>/... instead of a global flat plans/ namespace
  • scope team cleanup to the current team's plan directory and only remove legacy flat plan files that the team actually referenced
  • add regression coverage for team-scoped plan storage, legacy fallback, cross-team cleanup isolation, and nonexistent-team cleanup

Root cause

PlanManager wrote plans into a global plans/<agent>-<id>.md layout, while TeamManager.cleanup(team) deleted every plans/*.md file. That meant cleaning one team could delete another team's plans, and even cleaning a nonexistent team could wipe global plan files.

Testing

  • ClawTeam/.venv/bin/python -m pytest -q tests/test_plan_storage.py tests/test_inbox_routing.py
  • ClawTeam/.venv/bin/python -m ruff check clawteam/team/plan.py clawteam/team/manager.py tests/test_plan_storage.py tests/test_inbox_routing.py
  • /ClawTeam/.venv/bin/python -m compileall clawteam

@tjb-tech tjb-tech merged commit c16b3c3 into HKUDS:main Mar 18, 2026
7 checks passed
Longado pushed a commit to Longado/ClawTeam that referenced this pull request Mar 18, 2026
Combines the best of both open PRs, resolving their overlapping approaches
and applying all 6 fixes that are not yet in main:

**mailbox.py**
- broadcast(): resolve logical agent names to inbox directory names before
  exclusion check, so the sender is not delivered their own broadcast when
  inboxes use user-prefixed format (e.g. "alice_worker" vs "worker")
  [from PR HKUDS#15]
- receive() / peek(): replace bare list comprehension with _parse_messages()
  helper that wraps each message in try/except, so a single corrupted file
  no longer crashes the entire fetch [from PR HKUDS#9]

**transport/file.py**
- fetch(consume=True): atomically rename msg file to .consumed before
  reading, so concurrent callers cannot both receive the same message
  [from PR HKUDS#15]

**cli/commands.py**
- config set / config get: derive valid_keys from ClawTeamConfig.model_fields
  instead of a hardcoded 3-item set, making all 7 config keys accessible;
  handle boolean fields (skip_permissions) correctly [from PR HKUDS#15]
- approve-join: return an error and exit(1) when no matching join request
  is found, instead of silently fabricating an agent name [from PR HKUDS#9]
- launch_team: read skip_permissions from config and pass it to be.spawn(),
  matching the behaviour of the standalone spawn command [from PR HKUDS#15]

Note: the plans-cleanup fix (PR HKUDS#9 subdirectory approach, PR HKUDS#15 member-filter
approach) was already merged via PR HKUDS#6 using the subdirectory strategy, so it
is intentionally excluded here.

All 135 existing tests pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
xzq-xu added a commit to xzq-xu/ClawTeam that referenced this pull request Mar 18, 2026
- Fix approve-join proceeding even when no matching join request is
  found, which silently added members with fabricated names. Now
  returns an error and exits.
- Fix receive()/peek() crashing on any corrupted message, which also
  caused valid consumed messages to be lost. Invalid messages are now
  skipped gracefully via per-message try/except.

Note: the plans cleanup fix was dropped from this PR as it was already
resolved upstream via PR HKUDS#6.

Made-with: Cursor
a24ibrah pushed a commit to a24ibrah/ClawTeam that referenced this pull request Mar 30, 2026
Fix team cleanup deleting plans from other teams
juntaochi added a commit to novix-science/ClawTeam-gstack that referenced this pull request Apr 20, 2026
- 8 failing tests covering ArtifactFrontmatterBase field shape,
  register/get/reset/list registry helpers, Pitfall HKUDS#6 None vs
  validation-failure distinction, and PhaseRegistry D-03 collision rule
- Plugin-manager integration test proves Plan 02-01's lazy-import
  guarded loop will wire end-to-end once the registry module lands (GREEN)
- All tests fail at RED with ModuleNotFoundError on clawteam.harness.evidence_schemas
juntaochi added a commit to novix-science/ClawTeam-gstack that referenced this pull request Apr 20, 2026
…se pydantic base

- ArtifactFrontmatterBase (pydantic BaseModel) with persona / step_label /
  done / artifact_type / created_at — shape parallel to TurnEnvelope
  (§02-CONTEXT lesson HKUDS#2: one model, two serialization surfaces)
- Module-level _REGISTERED dict + register_schema / get_schema /
  list_registered / reset_registry accessors — structural twin of
  PhaseRegistry (§02-CONTEXT lesson HKUDS#3)
- Duplicate artifact_type raises ValueError naming both existing and
  attempted classes (§02-CONTEXT D-03 collision rule)
- get_schema returns None for unregistered names — Pitfall HKUDS#6 caller
  distinguishes this from pydantic ValidationError
- Activates Plan 02-01's lazy-import guarded loop end-to-end; the Phase 0
  regression matrix stays 12/12 green
juntaochi added a commit to novix-science/ClawTeam-gstack that referenced this pull request Apr 20, 2026
…st_command + deploy_url

- 13 failing tests cover presence, frontmatter schema, stub detection (sections + blacklist), test-report rerun + cache-hit + exit-1 + timeout, and ship-notes deploy_url 2xx/non-2xx/URLError paths
- Test-local schema fixtures (DesignDoc/TestReport/ShipNotes) inherit from ArtifactFrontmatterBase; Phase 3 GstackSprintPlugin ships the real subclasses
- Pitfall HKUDS#4 proof: subprocess_runner injection seam asserted with shell-free list cmd + cwd pin + 300s timeout
- Pitfall HKUDS#6 proof: unregistered artifact_type surfaces 'Phase 3 plugin must register' message
- Pitfall HKUDS#10 proof: deploy_url_checker injection seam covers URLError offline-safety path
- RED: all tests fail with ModuleNotFoundError on clawteam.harness.evidence_gate
juntaochi added a commit to novix-science/ClawTeam-gstack that referenced this pull request Apr 27, 2026
- 3 new modules (high_impact_gate, conflict, backfill) wired into /learn
- 16 new tests green (6 gate + 5 conflict + 5 backfill)
- 94/94 memory+learn+plugin tests green; plugin registers 13 skills
- MEM-06 + QUALITY-10 closed
- Phase 6 Success Criteria HKUDS#6 + HKUDS#8 realized

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
juntaochi added a commit to novix-science/ClawTeam-gstack that referenced this pull request Apr 27, 2026
User request: "用tmux hook 把prompt注入进每一轮对话 包括身份和需要用的
skill 或者用tmux hook去做一些别的事情 总之tmux hook会是一个很好的技术".

Concept: agents drift over long sessions. CEO forgets to delegate (user
just hit this bug), engineer forgets which `clawteam` subcommands are
available, shipper forgets that `/ship` lives in the framework. A
periodic re-injection of "you are X; here's what you should use"
keeps them anchored.

Implementation:

1. `clawteam nudge <pane_id>` CLI command (new clawteam/nudge.py):
   - Looks up pane_id → session → team → agent via the persisted
     tmux_pane_map.json
   - Debounces (60s cooldown per pane) so repeated silence-hook firings
     don't spam the claude TUI
   - Reads the latest sprint state (current_phase + goal) for context
   - Builds a role-specific reminder text from _ROLE_NUDGES table
     (each role gets 2-3 lines: what you ARE + what commands you CAN
     run now). Appends "Goal: X · Phase: Y" when available.
   - Injects via `tmux send-keys -l <text>` + `send-keys Enter` so
     claude processes it as a user turn.
   - Silent-fail on any error (a noisy hook drowns the user's tmux).

2. tmux hook wiring (tmux_backend.py::_configure_nudge_hook):
   - `monitor-silence = 45s` on each window
   - `alert-silence` hook fires `clawteam nudge #{pane_id}` in the
     background (`run-shell -b`)
   - Opt-out via `CLAWTEAM_NUDGE_SECONDS=0` env var
   - Called from both `TmuxBackend.tile_panes()` (happy path) and
     `TmuxBackend.enable_mouse()` (the --windows non-tiled path) so
     every team gets nudge wiring regardless of layout choice.

3. pane_map normalization (tmux_backend.py::tile_panes):
   - Post-layout readback of pane_title returned claude's dynamic
     status strings like "⠐ CEO" / "✢ ENG-MGR" (spinner glyphs prefix).
   - Normalize by matching uppercase title content against the
     pre-merge window roster (roster_upper dict). Any title containing
     a known role (e.g. "⠐ CEO" contains "CEO") maps to the canonical
     lowercase role name.
   - pane_map.json now reliably stores {"0": "ceo", "1": "pm", ...}
     regardless of what claude's currently showing.

Real-env verified:
  clawteam go --no-attach --no-window "test"
  cat ~/.clawteam/teams/<team>/tmux_pane_map.json  → clean lowercase roster
  clawteam status                                    → Panes: 0=ceo 1=pm ...
  # wait for claude to boot
  clawteam nudge --force <pane_id>                   → injects role reminder
  tmux capture-pane                                  → sees "[nudge] Reminder:
                                                      you DELEGATE, never
                                                      implement. Decompose..."

Future uses of this hook infrastructure (brainstormed but not impl):
  - HKUDS#3 pane-died → log death reason, optional respawn
  - HKUDS#5 alert-activity → append pane output to activity.jsonl timeline
  - HKUDS#6 session-created → broadcast phase+goal to all panes
  - HKUDS#7 send-keys filter → intercept dangerous commands (rm -rf, force push)
  - HKUDS#10 pipe-pane → validate agent envelope JSON against schema

Tests: 30 solo/spawn_cli still green (nudge unit tests not added yet
— next commit candidate).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants