meshcode 2.11.160__tar.gz → 2.11.162__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. {meshcode-2.11.160 → meshcode-2.11.162}/PKG-INFO +2 -1
  2. {meshcode-2.11.160 → meshcode-2.11.162}/meshcode/__init__.py +1 -1
  3. {meshcode-2.11.160 → meshcode-2.11.162}/meshcode/meshcode_mcp/server.py +19 -11
  4. {meshcode-2.11.160 → meshcode-2.11.162}/meshcode/run_agent.py +14 -9
  5. {meshcode-2.11.160 → meshcode-2.11.162}/meshcode/setup_clients.py +18 -92
  6. {meshcode-2.11.160 → meshcode-2.11.162}/meshcode.egg-info/PKG-INFO +2 -1
  7. {meshcode-2.11.160 → meshcode-2.11.162}/meshcode.egg-info/SOURCES.txt +1 -0
  8. {meshcode-2.11.160 → meshcode-2.11.162}/meshcode.egg-info/requires.txt +1 -0
  9. {meshcode-2.11.160 → meshcode-2.11.162}/pyproject.toml +7 -1
  10. meshcode-2.11.162/tests/test_prompt_dedup_budget.py +161 -0
  11. {meshcode-2.11.160 → meshcode-2.11.162}/README.md +0 -0
  12. {meshcode-2.11.160 → meshcode-2.11.162}/meshcode/__main__.py +0 -0
  13. {meshcode-2.11.160 → meshcode-2.11.162}/meshcode/_launch_smoke.py +0 -0
  14. {meshcode-2.11.160 → meshcode-2.11.162}/meshcode/_session_handoff_template.py +0 -0
  15. {meshcode-2.11.160 → meshcode-2.11.162}/meshcode/_stop_hook_template.py +0 -0
  16. {meshcode-2.11.160 → meshcode-2.11.162}/meshcode/_update_guard.py +0 -0
  17. {meshcode-2.11.160 → meshcode-2.11.162}/meshcode/ascii_art.py +0 -0
  18. {meshcode-2.11.160 → meshcode-2.11.162}/meshcode/atomic_push.py +0 -0
  19. {meshcode-2.11.160 → meshcode-2.11.162}/meshcode/claude_update.py +0 -0
  20. {meshcode-2.11.160 → meshcode-2.11.162}/meshcode/cli.py +0 -0
  21. {meshcode-2.11.160 → meshcode-2.11.162}/meshcode/comms_v4.py +0 -0
  22. {meshcode-2.11.160 → meshcode-2.11.162}/meshcode/compat.py +0 -0
  23. {meshcode-2.11.160 → meshcode-2.11.162}/meshcode/daemon.py +0 -0
  24. {meshcode-2.11.160 → meshcode-2.11.162}/meshcode/date_parse.py +0 -0
  25. {meshcode-2.11.160 → meshcode-2.11.162}/meshcode/doctor.py +0 -0
  26. {meshcode-2.11.160 → meshcode-2.11.162}/meshcode/error_hints.py +0 -0
  27. {meshcode-2.11.160 → meshcode-2.11.162}/meshcode/exceptions.py +0 -0
  28. {meshcode-2.11.160 → meshcode-2.11.162}/meshcode/hooks/__init__.py +0 -0
  29. {meshcode-2.11.160 → meshcode-2.11.162}/meshcode/hooks/push_guard.py +0 -0
  30. {meshcode-2.11.160 → meshcode-2.11.162}/meshcode/hooks/repo_path_lock.py +0 -0
  31. {meshcode-2.11.160 → meshcode-2.11.162}/meshcode/hostd.py +0 -0
  32. {meshcode-2.11.160 → meshcode-2.11.162}/meshcode/invites.py +0 -0
  33. {meshcode-2.11.160 → meshcode-2.11.162}/meshcode/launcher.py +0 -0
  34. {meshcode-2.11.160 → meshcode-2.11.162}/meshcode/launcher_install.py +0 -0
  35. {meshcode-2.11.160 → meshcode-2.11.162}/meshcode/meshcode_mcp/__init__.py +0 -0
  36. {meshcode-2.11.160 → meshcode-2.11.162}/meshcode/meshcode_mcp/__main__.py +0 -0
  37. {meshcode-2.11.160 → meshcode-2.11.162}/meshcode/meshcode_mcp/backend.py +0 -0
  38. {meshcode-2.11.160 → meshcode-2.11.162}/meshcode/meshcode_mcp/realtime.py +0 -0
  39. {meshcode-2.11.160 → meshcode-2.11.162}/meshcode/meshcode_mcp/sleep_signals.py +0 -0
  40. {meshcode-2.11.160 → meshcode-2.11.162}/meshcode/meshcode_mcp/test_backend.py +0 -0
  41. {meshcode-2.11.160 → meshcode-2.11.162}/meshcode/meshcode_mcp/test_boot_timing.py +0 -0
  42. {meshcode-2.11.160 → meshcode-2.11.162}/meshcode/meshcode_mcp/test_install_guard.py +0 -0
  43. {meshcode-2.11.160 → meshcode-2.11.162}/meshcode/meshcode_mcp/test_prefs_claude_version.py +0 -0
  44. {meshcode-2.11.160 → meshcode-2.11.162}/meshcode/meshcode_mcp/test_realtime.py +0 -0
  45. {meshcode-2.11.160 → meshcode-2.11.162}/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
  46. {meshcode-2.11.160 → meshcode-2.11.162}/meshcode/preferences.py +0 -0
  47. {meshcode-2.11.160 → meshcode-2.11.162}/meshcode/protocol_handler.py +0 -0
  48. {meshcode-2.11.160 → meshcode-2.11.162}/meshcode/protocol_v2.py +0 -0
  49. {meshcode-2.11.160 → meshcode-2.11.162}/meshcode/quickstart.py +0 -0
  50. {meshcode-2.11.160 → meshcode-2.11.162}/meshcode/rpc_allowlist.py +0 -0
  51. {meshcode-2.11.160 → meshcode-2.11.162}/meshcode/scripts/check_secrets.py +0 -0
  52. {meshcode-2.11.160 → meshcode-2.11.162}/meshcode/scripts/race_rate_harness.py +0 -0
  53. {meshcode-2.11.160 → meshcode-2.11.162}/meshcode/secrets.py +0 -0
  54. {meshcode-2.11.160 → meshcode-2.11.162}/meshcode/self_update.py +0 -0
  55. {meshcode-2.11.160 → meshcode-2.11.162}/meshcode/supervisor.py +0 -0
  56. {meshcode-2.11.160 → meshcode-2.11.162}/meshcode/up.py +0 -0
  57. {meshcode-2.11.160 → meshcode-2.11.162}/meshcode/upload.py +0 -0
  58. {meshcode-2.11.160 → meshcode-2.11.162}/meshcode.egg-info/dependency_links.txt +0 -0
  59. {meshcode-2.11.160 → meshcode-2.11.162}/meshcode.egg-info/entry_points.txt +0 -0
  60. {meshcode-2.11.160 → meshcode-2.11.162}/meshcode.egg-info/top_level.txt +0 -0
  61. {meshcode-2.11.160 → meshcode-2.11.162}/setup.cfg +0 -0
  62. {meshcode-2.11.160 → meshcode-2.11.162}/tests/test_auto_update_hardening.py +0 -0
  63. {meshcode-2.11.160 → meshcode-2.11.162}/tests/test_autonomous_closegap_1.py +0 -0
  64. {meshcode-2.11.160 → meshcode-2.11.162}/tests/test_autonomous_closegap_2.py +0 -0
  65. {meshcode-2.11.160 → meshcode-2.11.162}/tests/test_autonomous_closegap_3.py +0 -0
  66. {meshcode-2.11.160 → meshcode-2.11.162}/tests/test_autonomous_prompt_inject.py +0 -0
  67. {meshcode-2.11.160 → meshcode-2.11.162}/tests/test_boot_bug_regression.py +0 -0
  68. {meshcode-2.11.160 → meshcode-2.11.162}/tests/test_color_truecolor.py +0 -0
  69. {meshcode-2.11.160 → meshcode-2.11.162}/tests/test_core.py +0 -0
  70. {meshcode-2.11.160 → meshcode-2.11.162}/tests/test_cross_agent_messaging.py +0 -0
  71. {meshcode-2.11.160 → meshcode-2.11.162}/tests/test_date_parse.py +0 -0
  72. {meshcode-2.11.160 → meshcode-2.11.162}/tests/test_doctor.py +0 -0
  73. {meshcode-2.11.160 → meshcode-2.11.162}/tests/test_ensure_boot_env_urgent_wake.py +0 -0
  74. {meshcode-2.11.160 → meshcode-2.11.162}/tests/test_epistemic_v1_python_sdk.py +0 -0
  75. {meshcode-2.11.160 → meshcode-2.11.162}/tests/test_epistemic_v1_stop_conditions.py +0 -0
  76. {meshcode-2.11.160 → meshcode-2.11.162}/tests/test_esc_deaf_state.py +0 -0
  77. {meshcode-2.11.160 → meshcode-2.11.162}/tests/test_exceptions.py +0 -0
  78. {meshcode-2.11.160 → meshcode-2.11.162}/tests/test_file_upload.py +0 -0
  79. {meshcode-2.11.160 → meshcode-2.11.162}/tests/test_fleet_reaper.py +0 -0
  80. {meshcode-2.11.160 → meshcode-2.11.162}/tests/test_hostd_launch_pinned_env.py +0 -0
  81. {meshcode-2.11.160 → meshcode-2.11.162}/tests/test_hostd_serve_discovery_split.py +0 -0
  82. {meshcode-2.11.160 → meshcode-2.11.162}/tests/test_hostd_zombie_sessions.py +0 -0
  83. {meshcode-2.11.160 → meshcode-2.11.162}/tests/test_init_device_code.py +0 -0
  84. {meshcode-2.11.160 → meshcode-2.11.162}/tests/test_install_guard.py +0 -0
  85. {meshcode-2.11.160 → meshcode-2.11.162}/tests/test_launch_smoke.py +0 -0
  86. {meshcode-2.11.160 → meshcode-2.11.162}/tests/test_lease_sigterm_release.py +0 -0
  87. {meshcode-2.11.160 → meshcode-2.11.162}/tests/test_live_mesh_guard.py +0 -0
  88. {meshcode-2.11.160 → meshcode-2.11.162}/tests/test_mark_read_batch.py +0 -0
  89. {meshcode-2.11.160 → meshcode-2.11.162}/tests/test_marketplace_ratings.py +0 -0
  90. {meshcode-2.11.160 → meshcode-2.11.162}/tests/test_migration_integrity.py +0 -0
  91. {meshcode-2.11.160 → meshcode-2.11.162}/tests/test_no_appleevents_on_sweep.py +0 -0
  92. {meshcode-2.11.160 → meshcode-2.11.162}/tests/test_preflight_hb_gate.py +0 -0
  93. {meshcode-2.11.160 → meshcode-2.11.162}/tests/test_pretrust_claude.py +0 -0
  94. {meshcode-2.11.160 → meshcode-2.11.162}/tests/test_push_guard.py +0 -0
  95. {meshcode-2.11.160 → meshcode-2.11.162}/tests/test_realtime_event_freshness.py +0 -0
  96. {meshcode-2.11.160 → meshcode-2.11.162}/tests/test_replica_base_workspace_fallback.py +0 -0
  97. {meshcode-2.11.160 → meshcode-2.11.162}/tests/test_replica_boot_protocol_unconditional.py +0 -0
  98. {meshcode-2.11.160 → meshcode-2.11.162}/tests/test_rls_cross_tenant.py +0 -0
  99. {meshcode-2.11.160 → meshcode-2.11.162}/tests/test_rm_guard.py +0 -0
  100. {meshcode-2.11.160 → meshcode-2.11.162}/tests/test_rpc_grants.py +0 -0
  101. {meshcode-2.11.160 → meshcode-2.11.162}/tests/test_rpc_migrations.py +0 -0
  102. {meshcode-2.11.160 → meshcode-2.11.162}/tests/test_run_agent_dry_run.py +0 -0
  103. {meshcode-2.11.160 → meshcode-2.11.162}/tests/test_run_agent_no_server_import.py +0 -0
  104. {meshcode-2.11.160 → meshcode-2.11.162}/tests/test_security_regressions.py +0 -0
  105. {meshcode-2.11.160 → meshcode-2.11.162}/tests/test_self_update_user_site.py +0 -0
  106. {meshcode-2.11.160 → meshcode-2.11.162}/tests/test_sentinel.py +0 -0
  107. {meshcode-2.11.160 → meshcode-2.11.162}/tests/test_session_replay_gate.py +0 -0
  108. {meshcode-2.11.160 → meshcode-2.11.162}/tests/test_setup_path.py +0 -0
  109. {meshcode-2.11.160 → meshcode-2.11.162}/tests/test_sleep_signals.py +0 -0
  110. {meshcode-2.11.160 → meshcode-2.11.162}/tests/test_status_enum_coverage.py +0 -0
  111. {meshcode-2.11.160 → meshcode-2.11.162}/tests/test_stay_on_loop_hook.py +0 -0
  112. {meshcode-2.11.160 → meshcode-2.11.162}/tests/test_stop_ghost_terminal.py +0 -0
  113. {meshcode-2.11.160 → meshcode-2.11.162}/tests/test_task_progress.py +0 -0
  114. {meshcode-2.11.160 → meshcode-2.11.162}/tests/test_terminal_lifecycle.py +0 -0
  115. {meshcode-2.11.160 → meshcode-2.11.162}/tests/test_up_launch_cmd.py +0 -0
  116. {meshcode-2.11.160 → meshcode-2.11.162}/tests/test_update_guard.py +0 -0
  117. {meshcode-2.11.160 → meshcode-2.11.162}/tests/test_urgent_wake_tmux.py +0 -0
  118. {meshcode-2.11.160 → meshcode-2.11.162}/tests/test_wait_open_tasks_contradiction.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: meshcode
3
- Version: 2.11.160
3
+ Version: 2.11.162
4
4
  Summary: Real-time communication between AI agents — Supabase-backed CLI
5
5
  Author-email: MeshCode <hello@meshcode.io>
6
6
  License: MIT
@@ -23,6 +23,7 @@ Requires-Dist: websockets>=12.0
23
23
  Requires-Dist: realtime>=2.0.0
24
24
  Requires-Dist: keyring>=24.0
25
25
  Requires-Dist: cryptography>=41.0
26
+ Requires-Dist: psutil>=5.9.0
26
27
  Provides-Extra: test
27
28
  Requires-Dist: pytest>=8; extra == "test"
28
29
  Provides-Extra: dev
@@ -1,5 +1,5 @@
1
1
  """MeshCode — Real-time communication between AI agents."""
2
- __version__ = "2.11.160"
2
+ __version__ = "2.11.162"
3
3
 
4
4
  # Exception hierarchy — eagerly imported (lightweight, no deps)
5
5
  from meshcode.exceptions import ( # noqa: F401
@@ -1936,28 +1936,36 @@ def _build_instructions() -> str:
1936
1936
 
1937
1937
  base = f"""You are agent "{AGENT_NAME}" in meshwork "{PROJECT_NAME}".{role_block}{launch_block}
1938
1938
 
1939
+ USER INTENT DOMINATES. The human's concrete request is the objective — mesh protocol is HOW you operate, never WHAT you build. Do exactly what is asked: no unrequested scope (no new infra/Docker/refactors/files unless explicitly requested), and when given a concrete directive ("reduce the font size") do THAT first and verify it before any housekeeping. If protocol and the user's literal ask conflict, the user wins.
1940
+
1939
1941
  {_db_loop}LOOP (#1 rule): act → meshcode_wait() → repeat. Never exit/stop without calling meshcode_wait(). EXIT IMMEDIATELY when wait returns must_exit=True (set status=sleeping then end session). Other exits: user says stop, fatal error. Timeout → re-call with 2x (cap 1800s).
1940
1942
 
1941
- RULES: MCP tools only. Tasks > messages. Messages <100 tokens (long task). No empty acks, JSON only. Thread via in_reply_to. sensitive=True for secrets. Sync vs async: for turn-based/shared-state work (chess, lock-step, "who goes first"), use meshcode_call (sync RPC, 30s) async meshcode_send crosses ~50%/turn between same-model agents and yields-pongs.
1943
+ CLOSE TASKS IMMEDIATELY (#2 rule): the instant you finish/ship work for a claimed task, call meshcode_task_complete BEFORE re-entering wait. No "I'll close it after one more thing." No lingering in_progress while you do other work stale in_progress lies to the dashboard. Needs human review → requires_approval=true at create, or task_complete routes to in_review if a reviewer is set.
1942
1944
 
1943
- REPLY TO HUMANS VIA THE MESH, NOT THE TERMINAL (product default, Samuel 2026-06-04): when you answer a human (sammybenu/Samuel/ian/fis), you MUST meshcode_send to the mesh. The human watches the DASHBOARD — your Claude Code terminal text and your thinking are INVISIBLE to them, so a terminal-only reply reads as silence ("¿por qué no me contestas?" even while you "answered"). meshcode_send is the ONLY channel they see. To humans write plain prose in THEIR language (Spanish for Samuel), never JSON; JSON-only is for agent↔agent.
1945
+ WORK ASSIGNED TASKS IMMEDIATELY (#3 rule): when meshcode_wait returns pending_tasks or auto_started_task, your NEXT action MUST be to work that task. Don't re-enter wait, don't ask "what should I do" the description tells you. read execute task_complete wait. One by one until empty.
1944
1946
 
1945
- CLOSE TASKS IMMEDIATELY (#2 rule, sammybenu 2026-05-22T21:06Z): every time you finish/ship/deliver work for a claimed task, call meshcode_task_complete BEFORE re-entering wait. NO "I'll close it after one more thing." NO leaving claimed tasks lingering in_progress while you do something else that creates phantom in-progress on the dashboard and the human gets angry. If the work needs human review, set requires_approval=true at task_create OR call meshcode_task_complete (it routes to in_review if reviewer set). The mesh dashboard reflects mc_tasks.status in real-time; stale in_progress = lying to the human.
1947
+ REPLY TO HUMANS VIA THE MESH, NOT THE TERMINAL (Samuel 2026-06-04): when you answer a human (sammybenu/Samuel/ian/fis) you MUST meshcode_send to the mesh. The human watches the DASHBOARD your terminal text + thinking are INVISIBLE; a terminal-only reply reads as silence. Write plain prose in THEIR language (Spanish for Samuel), never JSON (JSON is agent↔agent).
1946
1948
 
1947
- WORK ASSIGNED TASKS IMMEDIATELY (#3 rule): when meshcode_wait returns pending_tasks or auto_started_task, your NEXT action MUST be to work that task. Do NOT re-enter wait, do NOT ask "what should I do" the task description tells you. Sequence: read task descriptionexecute the work meshcode_task_complete meshcode_wait (which surfaces the next task). One by one until the queue is empty.
1949
+ RULES: MCP tools only. Tasks > messages (messages <100 tokens, long task). No empty acks, JSON only. Thread via in_reply_to. sensitive=True for secrets/PII. Sync vs async: turn-based/shared-state (chess, lock-step, "who goes first")meshcode_call (sync RPC); informing/signalingmeshcode_send (async, crosses ~50%/turn between same-model agents).
1948
1950
 
1949
- SESSION START (run NOW, don't wait for input). If tool schemas are deferred:
1950
- ToolSearch(query="select:meshcode_set_status,meshcode_check,meshcode_tasks,meshcode_auto_wake,meshcode_status,meshcode_wait,meshcode_send,meshcode_call,meshcode_claim,meshcode_task_claim,meshcode_task_complete,meshcode_remember,meshcode_recall")
1951
- Then: set_status(online,ready) check() tasks() auto_wake() status() wait(). Don't ask user "what to work on" the mesh tells you.
1951
+ GIT-PUSH GOLDEN RULE (Samuel wt10): NEVER git push unless (1) the diff contains NO secrets AND (2) `git remote -v` confirms the remote is verified-ours + on the authorized allowlist. A remote not verified as ours = DO NOT PUSH, escalate to Security Chief (anfexi incident: core IP pushed to an ex-employer repo). MESHCODE_PUSH_GUARD enforces this at the pre-push hook; do not bypass.
1952
+
1953
+ SAFE SHELL: never run an unguarded `rm` on a variable/glob path — Claude Code hard-pauses on `rm $VAR/...` and root/home removals (cannot be flag-bypassed). Guard: `[ -n "$VAR" ] && [ -d "$VAR" ] && rm "$VAR"/*.ext`, or `find "$VAR" -maxdepth 1 -name '*.ext' -type f -delete`. Never `rm -rf /`, `rm -rf ~`, `rm -rf $UNSET/`.
1952
1954
 
1953
- COMMUNICATE BY CALLING TOOLS, not by thinking aloud. Cross-mesh: send(to="agent@meshwork"). Reference docs (memory/scratchpad/account ops) recall agent_protocol_quick_ref when needed.
1955
+ USE SKILLS + SUBAGENTS (mandatory, Samuel hard rule): invoke the Skill tool whenever ANY skill matches (even slightly) BEFORE acting; dispatch subagents for multi-file search/audits. Samuel flagged skipping skills/subagents as underperforming.
1956
+
1957
+ MOBILE-FIRST UI GATE (Samuel MOBILE-FIRST-2): before task_complete on ANY task touching user-visible UI, run Playwright HEADLESS (headless:true — NEVER a visible browser window on the user's machine) at 375x667, 390x844, 768x1024 and put the 3 screenshot paths + console-error count in the summary. Backend-only task → state "verified: backend-only, no UI surface". (Full how-to is in your repo CLAUDE.md.)
1958
+
1959
+ SESSION START (run NOW, don't wait for input). If tool schemas are deferred:
1960
+ ToolSearch(query="select:meshcode_set_status,meshcode_boot,meshcode_wait,meshcode_send,meshcode_call,meshcode_task_claim,meshcode_task_complete,meshcode_remember,meshcode_recall")
1961
+ Then: set_status(online,ready) → meshcode_boot() → meshcode_wait(). Don't ask "what to work on" — the mesh tells you.
1954
1962
 
1955
- Memory hints with open_contradictions take a -0.2 ranking penalty — treat as a flag, not a veto.
1963
+ Memory hints with open_contradictions take a -0.2 ranking penalty — flag, not veto.
1956
1964
 
1957
1965
  ESCALATION RULES:
1958
- - MUST escalate to human: destructive ops (drop/delete/rm -rf), irreversible changes (force-push main, mig without rollback), product-direction decisions (what feature next), legal/compliance, security (auth/secrets/PII), spend > $50 USD.
1966
+ - MUST escalate to human: destructive ops (drop/delete/rm -rf), irreversible changes (force-push main, mig without rollback), product-direction, legal/compliance, security (auth/secrets/PII), spend > $50 USD.
1959
1967
  - MUST NOT escalate: code style, implementation approach, naming, test strategy, migration ordering, refactor scope, library choice, which agent does what.
1960
- - GREY ZONE: scope changes, deadline trade-offs, cross-mesh assignments → try meshcode_call(to="mesh-commander", function="advise") first; escalate to human only if commander offline or responds "escalate".
1968
+ - GREY ZONE: scope/deadline trade-offs, cross-mesh assignments → meshcode_call(to="mesh-commander", function="advise") first; escalate to human only if commander offline or says "escalate".
1961
1969
  """
1962
1970
  # Inject commander protocol if this agent is a leader
1963
1971
  is_leader = _is_leader_agent()
@@ -1063,15 +1063,20 @@ def _provision_replica_mcp_from_base(project: str, agent: str, ws: "Path") -> bo
1063
1063
  MESHCODE_BOOT_PROTOCOL = """You are agent {agent} in MeshCode meshwork {project}. Role: {role}.
1064
1064
  You are running INSIDE the repo at {repo} (your cwd) — operate here like a normal terminal opened in this repo: read its CLAUDE.md + local memory, work here, and do NOT leave it (a hard repo-path lock denies file ops outside it).
1065
1065
 
1066
- ON SESSION START (run NOW, don't idle/greet): if meshcode_* tools are deferred, FIRST call ToolSearch(query="select:meshcode_set_status,meshcode_boot,meshcode_wait,meshcode_send,meshcode_task_complete"). Then 1) meshcode_set_status(status="online",task="ready"); 2) meshcode_boot(); 3) meshcode_wait().
1067
-
1068
- PERMANENT LOOP (#1 rule): after boot and after EVERY action, your next tool call MUST be meshcode_wait(). act -> (optional meshcode_send) -> meshcode_wait() -> repeat. NEVER exit/stop without calling meshcode_wait(). Only exits: user says stop/sleep/exit, commander got_done/sleep auth, or fatal error. If wait times out, re-call with 2x timeout (cap 1800s).
1069
-
1070
- RULES: MCP tools only (don't shell out to the meshcode CLI). Tasks > messages; messages <100 tokens (signals), no empty acks, JSON, thread via in_reply_to. Close tasks immediately when done (meshcode_task_complete); work assigned tasks immediately. Sync vs async: turn-based/shared-state -> meshcode_call; informing -> meshcode_send. meshcode_remember(key,value) for reusable learnings.
1071
-
1072
- SAFE SHELL (data-loss guard, task 5d050633): NEVER run an unguarded `rm` on a variable/glob path. Claude Code has a HARDCODED circuit breaker that PAUSES you for "proceed yes/no" approval on `rm $VAR/...` (possibly-empty variable) and on root/home removals it CANNOT be bypassed by any flag. To stay autonomous (no pause) AND never delete the wrong thing, always guard: `[ -n "$VAR" ] && [ -d "$VAR" ] && rm "$VAR"/*.ext`, or use `find "$VAR" -maxdepth 1 -name '*.ext' -type f -delete`. Never `rm -rf /`, `rm -rf ~`, or `rm -rf $UNSET/`.
1073
-
1074
- ALWAYS USE SKILLS + SUBAGENTS (mandatory): invoke the Skill tool whenever any skill matches (even 1%) BEFORE acting; dispatch subagents for multi-file search/audits. Samuel flagged skipping skills/subagents as underperforming — hard rule."""
1066
+ Your FULL operating protocol is injected by the meshcode MCP server's instructions (the canonical home). The bullets below are a SLIM SAFETY-NET MIRROR of the non-negotiables, in case MCP init is delayed at boot — follow the MCP instructions when they load.
1067
+
1068
+ ON SESSION START (run NOW, don't idle/greet): if meshcode_* tools are deferred, FIRST call ToolSearch(query="select:meshcode_set_status,meshcode_boot,meshcode_wait,meshcode_send,meshcode_task_complete"). Then set_status(online,ready) -> meshcode_boot() -> meshcode_wait().
1069
+
1070
+ CORE NON-NEGOTIABLES (mirror):
1071
+ - USER INTENT DOMINATES: do exactly what the human asked; no unrequested scope. If protocol and the literal ask conflict, the user wins.
1072
+ - LOOP (#1): act -> meshcode_wait() -> repeat. Never exit without meshcode_wait(). Exit only on must_exit=True (set status=sleeping) / user stop / fatal error. Timeout -> re-call 2x (cap 1800s).
1073
+ - CLOSE TASKS (#2): the instant you finish claimed work, meshcode_task_complete BEFORE re-entering wait. No lingering in_progress.
1074
+ - WORK ASSIGNED (#3): wait returns pending_tasks/auto_started_task -> your NEXT action works that task. read -> execute -> task_complete -> wait.
1075
+ - REPLY TO HUMANS VIA THE MESH (not the terminal): meshcode_send plain prose in their language (Spanish for Samuel); terminal text is invisible on the dashboard. JSON is agent<->agent only.
1076
+ - MCP tools only (don't shell out to the meshcode CLI). Tasks > messages (<100 tokens, signals). Thread via in_reply_to. sensitive=True for secrets/PII.
1077
+ - GIT-PUSH GOLDEN RULE: NEVER git push unless the diff has NO secrets AND `git remote -v` confirms a verified-ours allowlisted remote. Unverified remote = DO NOT PUSH, escalate.
1078
+ - SAFE SHELL: never run an unguarded `rm` on a variable/glob path. Guard: `[ -n "$VAR" ] && [ -d "$VAR" ] && rm "$VAR"/*.ext`, or `find "$VAR" -maxdepth 1 -name '*.ext' -type f -delete`. Never `rm -rf /`, `rm -rf ~`, `rm -rf $UNSET/`.
1079
+ - USE SKILLS + SUBAGENTS (mandatory, Samuel hard rule): invoke the Skill tool whenever ANY skill matches (even slightly) BEFORE acting; dispatch subagents for multi-file search/audits."""
1075
1080
 
1076
1081
 
1077
1082
  def ensure_repo_lock_hook_installed():
@@ -1275,82 +1275,21 @@ work in a different repo by `cd`ing elsewhere after launch.
1275
1275
  You are agent **{agent}** in MeshCode meshwork **{project}**.
1276
1276
  Role: {role or "(set in dashboard)"}
1277
1277
 
1278
- ## ON SESSION START DO THIS IMMEDIATELY (no matter what the user types)
1279
-
1280
- The moment this session opens whether the user typed `boot`, `hi`, nothing,
1281
- or anything else run the full boot protocol. Do NOT reply with only a
1282
- greeting or memory dump and then idle. Do NOT ask "what do you want to work
1283
- on" the mesh tells you via tasks/messages.
1284
-
1285
- If the meshcode_* tool schemas are deferred in your client, your FIRST tool
1286
- call MUST be:
1287
-
1288
- ```
1289
- ToolSearch(query="select:meshcode_set_status,meshcode_boot,meshcode_check,meshcode_tasks,meshcode_auto_wake,meshcode_status,meshcode_wait,meshcode_send,meshcode_call,meshcode_claim,meshcode_task_claim,meshcode_task_complete,meshcode_remember,meshcode_recall")
1290
- ```
1291
-
1292
- Then run the boot sequence:
1293
-
1294
- 1. `meshcode_set_status(status="online", task="ready")`
1295
- 2. `meshcode_boot()` — single RPC returning inbox + tasks + mesh status + persona + health + memory hints (replaces check+tasks+status+auto_wake+recall in one round-trip; mig 271). Falls back gracefully on older projects.
1296
- 3. `meshcode_wait()` — enter the permanent loop (see next section)
1297
-
1298
- Legacy boot order (only if `meshcode_boot()` returns `ok: false` with `mc_boot_unavailable`):
1299
-
1300
- a. `meshcode_check()` — read NEW messages
1301
- b. `meshcode_tasks()` — see assigned/pending tasks
1302
- c. `meshcode_auto_wake()` — scan meshwork health
1303
- d. `meshcode_status()` — see who's online
1304
- e. `meshcode_wait()` — enter the loop
1305
-
1306
- ## PERMANENT LOOP (THE #1 RULE)
1307
-
1308
- After the boot sequence — and after **EVERY** subsequent action — your next
1309
- tool call MUST be `meshcode_wait()`. The loop:
1310
-
1311
- ```
1312
- act → (optional meshcode_send) → meshcode_wait() → repeat
1313
- ```
1314
-
1315
- NEVER exit. NEVER stop. NEVER say "standing by" / "let me know" / "I'm here"
1316
- without actually calling `meshcode_wait()`. The ONLY exits:
1317
- - the human user explicitly says "stop" / "sleep" / "exit",
1318
- - the commander broadcasts a got_done / sleep authorization,
1319
- - a fatal error makes continuation impossible.
1320
-
1321
- If `meshcode_wait()` times out, call it again with a 2× longer timeout (cap 1800s).
1322
-
1323
- ## RULES
1324
-
1325
- - Use MCP tools. Don't shell out to the `meshcode` CLI from inside the session.
1326
- - Tasks > messages. Use `meshcode_task_create / task_claim / task_complete`
1327
- for trackable work. Keep messages <100 tokens (signals only).
1328
- - No empty acks. JSON reports only.
1329
- - **Reply to humans via the mesh, NOT the terminal** (product default): when you
1330
- answer a human (Samuel/sammybenu/ian/fis), `meshcode_send` to the mesh. The
1331
- human watches the DASHBOARD — your Claude Code terminal text + thinking are
1332
- invisible to them, so a terminal-only reply reads as silence. Write plain prose
1333
- in their language (Spanish for Samuel), never JSON — JSON is for agent↔agent.
1334
- - Threading: pass `in_reply_to`.
1335
- - Sync vs async: for turn-based or shared-state coordination (chess, single-writer
1336
- doc, lock-step handoffs, "who goes first" decisions), prefer
1337
- `meshcode_call(to, function, args, timeout_seconds=30)` over `meshcode_send`.
1338
- `send` is fire-and-forget and crosses on the wire at ~50%/turn between
1339
- same-model agents, producing yield-pong. `call` is synchronous RPC: blocks
1340
- until the callee responds with a matching call_id, max 60s. See
1341
- "When to use sync vs async" below.
1342
- - Multi-recipient: when the same payload goes to ≥2 agents, use
1343
- `meshcode_send(to=["a","b"])` or CSV `"a,b,c"` — never N single-sends.
1344
- Server fans out via `mc_send_multi` with a shared `group_id` and the FE
1345
- collapses the row. Saves N-1 RPCs + round-trips. Cross-mesh `agent@meshwork`
1346
- is single-recipient only (mixed lists rejected v1).
1347
- - `sensitive=True` for secrets / PII.
1348
- - Memory: `meshcode_remember(key, value)` for reusable learnings. Don't dump
1349
- task summaries into memory — tasks already persist.
1350
- - **ALWAYS USE SKILLS + SUBAGENTS (mandatory):** invoke the Skill tool whenever
1351
- any skill matches (even 1%) BEFORE acting; dispatch subagents for multi-file
1352
- search/audits. Samuel flagged skipping skills/subagents as underperforming —
1353
- hard rule.
1278
+ > **Your operating protocol lives in the meshcode MCP server's instructions**
1279
+ > (injected at session start — the canonical home for the boot sequence, the
1280
+ > permanent `meshcode_wait()` loop, task/message rules, escalation, and the
1281
+ > git-push + safe-shell guards). This file is **project-specific** guidance only.
1282
+ > If the MCP instructions and this file ever conflict, the MCP instructions win.
1283
+ > Boot now (don't idle/greet): if meshcode_* tools are deferred,
1284
+ > `ToolSearch(query="select:meshcode_set_status,meshcode_boot,meshcode_wait,meshcode_send,meshcode_task_complete")`
1285
+ > then `set_status(online,ready)` `meshcode_boot()` `meshcode_wait()`.
1286
+
1287
+ ## Repo guard (this workspace)
1288
+
1289
+ This workspace is a real git repo. Before any `git push`: the diff must contain
1290
+ NO secrets AND `git remote -v` must confirm the remote is verified-ours +
1291
+ allowlisted. An unverified remote = DO NOT PUSH, escalate to the Security Chief.
1292
+ Never shell out to the `meshcode` CLI from inside the session — use MCP tools.
1354
1293
 
1355
1294
  ## Mobile-first UI verification (before task_complete)
1356
1295
 
@@ -1363,7 +1302,9 @@ Viewports (canonical):
1363
1302
  - iPhone 15 Pro 390 x 844
1364
1303
  - iPad 768 x 1024
1365
1304
 
1366
- Workflow (uses `mcp__playwright__browser_*` — load via ToolSearch if deferred):
1305
+ Workflow (uses `mcp__playwright__browser_*` — load via ToolSearch if deferred).
1306
+ ALWAYS run HEADLESS (`headless:true`) — never open a visible browser window on
1307
+ the user's machine:
1367
1308
 
1368
1309
  1. For each viewport: `browser_resize` → `browser_navigate(<route>)` →
1369
1310
  `browser_take_screenshot(filename="verify_<W>x<H>.png")` →
@@ -1390,21 +1331,6 @@ surface` in the summary so the rule is acknowledged.
1390
1331
  **Why:** Samuel mobile directive (MOBILE-FIRST-2). Catches mobile breakage at
1391
1332
  the agent before it reaches Samuel as a screenshot in chat.
1392
1333
 
1393
- ## When to use sync vs async
1394
-
1395
- | Pattern | Tool | Why |
1396
- |---|---|---|
1397
- | Status update, broadcast, signal | `meshcode_send` | async, no reply expected |
1398
- | Multi-recipient fan-out (≥2) | `meshcode_send(to=[…])` | one fan-out RPC, shared group_id |
1399
- | Turn-based work (chess, lock-step) | `meshcode_call` | both agents writing async crosses at ~50%/turn |
1400
- | "Who goes first" / role assignment | `meshcode_call` | yield-pong locks same-model pairs otherwise |
1401
- | Single-writer / shared-state edits | `meshcode_call` or `meshcode_claim` | atomic; no proposal-tennis |
1402
- | Request → structured response | `meshcode_call` | callee returns matched call_id, max 60s |
1403
- | Long-running task (>30s) | task + `meshcode_send` ack | RPC timeout would refuse |
1404
-
1405
- Rule of thumb: if the *next* action depends on the peer's *current* state, use
1406
- `meshcode_call`. If you're just informing/signaling, use `meshcode_send`.
1407
-
1408
1334
  ## Status reports (canonical handler)
1409
1335
 
1410
1336
  When another agent calls `meshcode_call(to="{agent}", function="status_report", args={{...}})`,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: meshcode
3
- Version: 2.11.160
3
+ Version: 2.11.162
4
4
  Summary: Real-time communication between AI agents — Supabase-backed CLI
5
5
  Author-email: MeshCode <hello@meshcode.io>
6
6
  License: MIT
@@ -23,6 +23,7 @@ Requires-Dist: websockets>=12.0
23
23
  Requires-Dist: realtime>=2.0.0
24
24
  Requires-Dist: keyring>=24.0
25
25
  Requires-Dist: cryptography>=41.0
26
+ Requires-Dist: psutil>=5.9.0
26
27
  Provides-Extra: test
27
28
  Requires-Dist: pytest>=8; extra == "test"
28
29
  Provides-Extra: dev
@@ -88,6 +88,7 @@ tests/test_migration_integrity.py
88
88
  tests/test_no_appleevents_on_sweep.py
89
89
  tests/test_preflight_hb_gate.py
90
90
  tests/test_pretrust_claude.py
91
+ tests/test_prompt_dedup_budget.py
91
92
  tests/test_push_guard.py
92
93
  tests/test_realtime_event_freshness.py
93
94
  tests/test_replica_base_workspace_fallback.py
@@ -3,6 +3,7 @@ websockets>=12.0
3
3
  realtime>=2.0.0
4
4
  keyring>=24.0
5
5
  cryptography>=41.0
6
+ psutil>=5.9.0
6
7
 
7
8
  [dev]
8
9
  build>=1.0
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "meshcode"
7
- version = "2.11.160"
7
+ version = "2.11.162"
8
8
  description = "Real-time communication between AI agents — Supabase-backed CLI"
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
@@ -17,6 +17,12 @@ dependencies = [
17
17
  "realtime>=2.0.0",
18
18
  "keyring>=24.0",
19
19
  "cryptography>=41.0",
20
+ # psutil: hostd PID discovery for the fail-closed anti-self-spawn + zombie-kill
21
+ # paths (tasks 89d50a14, 14e0760c). Was a lazy/optional import; promoted to a
22
+ # hard dep (task 03957df3, Ian P1) so the terminal-storm guard is ALWAYS armed —
23
+ # without psutil the discovery degrades and the running-cap can be defeated.
24
+ # Prebuilt wheels exist for all requires-python>=3.9 targets.
25
+ "psutil>=5.9.0",
20
26
  ]
21
27
  classifiers = [
22
28
  "Development Status :: 4 - Beta",
@@ -0,0 +1,161 @@
1
+ """Prompt-dedup CI guards (task 2bca50f1 / Dan-retro launch-reliability batch, 2026-06-23).
2
+
3
+ After deduping the agent operating protocol so the meshcode MCP server's
4
+ `_build_instructions()` is the CANONICAL home (run_agent.py's
5
+ MESHCODE_BOOT_PROTOCOL is a slim safety-net mirror; the provisioned workspace
6
+ CLAUDE.md is project-only), three properties must not regress:
7
+
8
+ 1. RULE-PRESENCE — every non-negotiable anchor still appears in the canonical
9
+ instructions. A dedup that silently drops a rule (vs. moving it) is a bug.
10
+ 2. TOKEN-BUDGET — the always-injected text (canonical instructions + the
11
+ boot-protocol mirror) stays under budget, so it never crowds the MCP
12
+ InitializeResult handshake window again (boot bug 00d73223 lineage).
13
+ 3. CACHE-STABILITY — neither always-injected string embeds a per-session
14
+ value (datetime / time / counter). Anthropic prompt-cache keys on the
15
+ static prefix; a clock token in the instructions busts the cache every
16
+ session.
17
+
18
+ Pure string assertions — no network, no Supabase (the builder defers all I/O).
19
+
20
+ Usage:
21
+ pytest tests/test_prompt_dedup_budget.py -v
22
+ """
23
+
24
+ import os
25
+ import re
26
+ import sys
27
+ import pathlib
28
+ from unittest import mock
29
+
30
+ import pytest
31
+
32
+ REPO = pathlib.Path(__file__).parent.parent
33
+ RUN_AGENT = REPO / "meshcode" / "run_agent.py"
34
+
35
+ # char/4 is the standard rough token approximation; the budget is deliberately
36
+ # generous (the real always-injected prefix is ~1800-2200 tok) so ordinary
37
+ # edits pass but a doubling/re-triplication trips the guard.
38
+ TOKEN_BUDGET = 2500
39
+ APPROX_CHARS_PER_TOKEN = 4
40
+
41
+ # The non-negotiables that MUST survive any dedup, by stable anchor substring.
42
+ REQUIRED_ANCHORS = [
43
+ "USER INTENT DOMINATES",
44
+ "LOOP (#1 rule)",
45
+ "CLOSE TASKS IMMEDIATELY (#2 rule)",
46
+ "WORK ASSIGNED TASKS IMMEDIATELY (#3 rule)",
47
+ "REPLY TO HUMANS VIA THE MESH",
48
+ "GIT-PUSH GOLDEN RULE",
49
+ "SAFE SHELL",
50
+ "MOBILE-FIRST UI GATE",
51
+ "sensitive=True",
52
+ "USE SKILLS + SUBAGENTS", # Samuel hard rule — retained through dedup
53
+ ]
54
+
55
+ # Tokens that would bust the prompt cache if embedded in always-injected text.
56
+ _CACHE_BUSTERS = re.compile(
57
+ r"datetime\.|time\.time\(|time\.monotonic|\.now\(|utcnow|"
58
+ r"strftime|uuid4\(|random\.|itertools\.count|next\(_?counter",
59
+ )
60
+
61
+
62
+ def _build_instructions(agent_name: str = "backend", role: str = "MCP-connected agent") -> str:
63
+ """Import server.py with backend mocked (no network) and return the canonical
64
+ instructions string for a given agent. Mirrors test_autonomous_prompt_inject."""
65
+ env = {
66
+ "MESHCODE_PROJECT": "test-project",
67
+ "MESHCODE_AGENT": agent_name,
68
+ "MESHCODE_PROJECT_ID": "00000000-0000-0000-0000-000000000000",
69
+ }
70
+ with mock.patch.dict(os.environ, env, clear=False):
71
+ for m in [k for k in sys.modules if k.startswith("meshcode.meshcode_mcp")]:
72
+ del sys.modules[m]
73
+ be_mock = mock.MagicMock()
74
+ be_mock.sb_rpc.return_value = {"ok": True, "status": "online"}
75
+ be_mock.register_agent.return_value = {"ok": True}
76
+ with mock.patch.dict(sys.modules, {"meshcode.meshcode_mcp.backend": be_mock}):
77
+ try:
78
+ from meshcode.meshcode_mcp import server
79
+ except Exception:
80
+ pytest.skip("server.py import failed (expected in isolated test env)")
81
+ orig_name, orig_role = server.AGENT_NAME, server._ROLE_DESCRIPTION
82
+ server.AGENT_NAME, server._ROLE_DESCRIPTION = agent_name, role
83
+ try:
84
+ return server._build_instructions()
85
+ finally:
86
+ server.AGENT_NAME, server._ROLE_DESCRIPTION = orig_name, orig_role
87
+
88
+
89
+ def _boot_protocol_source() -> str:
90
+ """The MESHCODE_BOOT_PROTOCOL literal from run_agent.py (read statically — the
91
+ launch fn execs claude + chdirs, so the module isn't unit-callable)."""
92
+ src = RUN_AGENT.read_text(encoding="utf-8")
93
+ m = re.search(r'MESHCODE_BOOT_PROTOCOL\s*=\s*"""(.*?)"""', src, re.DOTALL)
94
+ assert m, "MESHCODE_BOOT_PROTOCOL triple-quoted literal not found in run_agent.py"
95
+ return m.group(1)
96
+
97
+
98
+ class TestRulePresence:
99
+ def test_canonical_instructions_keep_every_anchor(self):
100
+ instr = _build_instructions("backend")
101
+ missing = [a for a in REQUIRED_ANCHORS if a not in instr]
102
+ assert not missing, (
103
+ f"Dedup dropped non-negotiable rule(s) from the canonical MCP "
104
+ f"instructions: {missing}. Move rules — never delete them."
105
+ )
106
+
107
+ def test_leader_also_keeps_every_anchor(self):
108
+ instr = _build_instructions("mesh-commander")
109
+ missing = [a for a in REQUIRED_ANCHORS if a not in instr]
110
+ assert not missing, f"Leader instructions missing anchor(s): {missing}"
111
+
112
+ def test_boot_mirror_keeps_core_safety_net(self):
113
+ """The slim run_agent mirror must still carry the boot-critical subset
114
+ (loop, close, work, reply, git-push, safe-shell, skills) for the
115
+ MCP-init-delayed window."""
116
+ boot = _boot_protocol_source()
117
+ for anchor in ("USER INTENT DOMINATES", "meshcode_wait()", "CLOSE TASKS",
118
+ "WORK ASSIGNED", "REPLY TO HUMANS", "GIT-PUSH GOLDEN RULE",
119
+ "SAFE SHELL", "USE SKILLS + SUBAGENTS"):
120
+ assert anchor in boot, f"boot-protocol mirror lost safety-net anchor: {anchor}"
121
+
122
+
123
+ class TestTokenBudget:
124
+ def test_always_injected_text_under_budget(self):
125
+ instr = _build_instructions("mesh-commander") # leader = the largest variant
126
+ boot = _boot_protocol_source()
127
+ approx_tokens = (len(instr) + len(boot)) // APPROX_CHARS_PER_TOKEN
128
+ assert approx_tokens <= TOKEN_BUDGET, (
129
+ f"Always-injected prompt text ~{approx_tokens} tok exceeds budget "
130
+ f"{TOKEN_BUDGET}. Dedup should shrink, not grow it — check for "
131
+ f"re-duplicated rules across the MCP instructions and the boot mirror."
132
+ )
133
+
134
+
135
+ class TestCacheStability:
136
+ def test_canonical_instructions_have_no_clock_tokens(self):
137
+ instr = _build_instructions("backend")
138
+ hit = _CACHE_BUSTERS.search(instr)
139
+ assert not hit, (
140
+ f"Canonical instructions embed a per-session token "
141
+ f"({hit.group(0) if hit else ''}) — this busts the Anthropic prompt "
142
+ f"cache every session. Keep always-injected text fully static."
143
+ )
144
+
145
+ def test_boot_protocol_has_no_clock_tokens(self):
146
+ boot = _boot_protocol_source()
147
+ hit = _CACHE_BUSTERS.search(boot)
148
+ assert not hit, (
149
+ f"Boot-protocol mirror embeds a per-session token "
150
+ f"({hit.group(0) if hit else ''}) — cache-busting; keep it static."
151
+ )
152
+
153
+
154
+ if __name__ == "__main__":
155
+ TestRulePresence().test_canonical_instructions_keep_every_anchor()
156
+ TestRulePresence().test_leader_also_keeps_every_anchor()
157
+ TestRulePresence().test_boot_mirror_keeps_core_safety_net()
158
+ TestTokenBudget().test_always_injected_text_under_budget()
159
+ TestCacheStability().test_canonical_instructions_have_no_clock_tokens()
160
+ TestCacheStability().test_boot_protocol_has_no_clock_tokens()
161
+ print("OK")
File without changes
File without changes
File without changes
File without changes