hcom 0.1.4__tar.gz → 0.1.6__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.

Potentially problematic release.


This version of hcom might be problematic. Click here for more details.

@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hcom
3
- Version: 0.1.4
4
- Summary: Lightweight CLI tool for real-time messaging between Claude Code subagents using hooks
3
+ Version: 0.1.6
4
+ Summary: Lightweight CLI tool for real-time communication between Claude Code subagents using hooks
5
5
  Author-email: aannoo <your@email.com>
6
6
  License: MIT
7
7
  Project-URL: Homepage, https://github.com/aannoo/claude-hook-comms
@@ -26,9 +26,9 @@ Classifier: Topic :: Communications
26
26
  Requires-Python: >=3.6
27
27
  Description-Content-Type: text/markdown
28
28
 
29
- # Claude Code Hook Comms
29
+ # hcom - Claude Hook Comms
30
30
 
31
- Lightweight CLI tool for real-time communication between claude code [subagents](https://docs.anthropic.com/en/docs/claude-code/sub-agents) using [hooks](https://docs.anthropic.com/en/docs/claude-code/hooks).
31
+ Lightweight CLI tool for real-time communication between Claude Code [subagents](https://docs.anthropic.com/en/docs/claude-code/sub-agents) using [hooks](https://docs.anthropic.com/en/docs/claude-code/hooks).
32
32
 
33
33
  ## 🦆 What It Does
34
34
 
@@ -38,7 +38,7 @@ Creates a group chat where you and multiple interactive Claude Code subagents ca
38
38
 
39
39
  ## 🦷 Features
40
40
 
41
- - **Multi-Terminal Launch** - Launch claude code subagents in new terminals
41
+ - **Multi-Terminal Launch** - Launch Claude Code subagents in new terminals
42
42
  - **Live Dashboard** - Real-time monitoring of all instances
43
43
  - **Multi-Agent Communication** - Claude instances talk to each other across projects
44
44
  - **@Mention Targeting** - Send messages to specific subagents or teams
@@ -154,7 +154,7 @@ HCOM_INSTANCE_HINTS="always update chat with progress" hcom open nice-subagent-b
154
154
  | `max_messages_per_delivery` | 50 | `HCOM_MAX_MESSAGES_PER_DELIVERY` | Messages delivered per batch |
155
155
  | `sender_name` | "bigboss" | `HCOM_SENDER_NAME` | Your name in chat |
156
156
  | `sender_emoji` | "🐳" | `HCOM_SENDER_EMOJI` | Your emoji icon |
157
- | `initial_prompt` | "Say hi" | `HCOM_INITIAL_PROMPT` | What new instances are told to do |
157
+ | `initial_prompt` | "Say hi in chat" | `HCOM_INITIAL_PROMPT` | What new instances are told to do |
158
158
  | `first_use_text` | "Essential, concise messages only" | `HCOM_FIRST_USE_TEXT` | Welcome message for instances |
159
159
  | `terminal_mode` | "new_window" | `HCOM_TERMINAL_MODE` | How to launch terminals ("new_window", "same_terminal", "show_commands") |
160
160
  | `terminal_command` | null | `HCOM_TERMINAL_COMMAND` | Custom terminal command (see Terminal Options) |
@@ -202,11 +202,11 @@ hcom adds hooks to your project directory's `.claude/settings.local.json`:
202
202
  - **Identity**: Each instance gets a unique name based on conversation UUID (e.g., "hovoa7")
203
203
  - **Persistence**: Names persist across `--resume` maintaining conversation context
204
204
  - **Status Detection**: Notification hook tracks permission requests and activity
205
- - **Agents**: When you run `hcom open researcher`, it loads an interactive claude session with a system prompt from `.claude/agents/researcher.md` (local) or `~/.claude/agents/researcher.md` (global)
205
+ - **Agents**: When you run `hcom open researcher`, it loads an interactive Claude session with a system prompt from `.claude/agents/researcher.md` (local) or `~/.claude/agents/researcher.md` (global). Agents can specify `model:` and `tools:` in YAML frontmatter
206
206
 
207
207
  ### Architecture
208
208
  - **Single conversation** - All instances share one global conversation
209
- - **Opt-in participation** - Only claude code instances launched with `hcom open` join the chat
209
+ - **Opt-in participation** - Only Claude Code instances launched with `hcom open` join the chat
210
210
  - **@-mention filtering** - Target messages to specific instances or teams
211
211
 
212
212
  ### File Structure
@@ -1,6 +1,6 @@
1
- # Claude Code Hook Comms
1
+ # hcom - Claude Hook Comms
2
2
 
3
- Lightweight CLI tool for real-time communication between claude code [subagents](https://docs.anthropic.com/en/docs/claude-code/sub-agents) using [hooks](https://docs.anthropic.com/en/docs/claude-code/hooks).
3
+ Lightweight CLI tool for real-time communication between Claude Code [subagents](https://docs.anthropic.com/en/docs/claude-code/sub-agents) using [hooks](https://docs.anthropic.com/en/docs/claude-code/hooks).
4
4
 
5
5
  ## 🦆 What It Does
6
6
 
@@ -10,7 +10,7 @@ Creates a group chat where you and multiple interactive Claude Code subagents ca
10
10
 
11
11
  ## 🦷 Features
12
12
 
13
- - **Multi-Terminal Launch** - Launch claude code subagents in new terminals
13
+ - **Multi-Terminal Launch** - Launch Claude Code subagents in new terminals
14
14
  - **Live Dashboard** - Real-time monitoring of all instances
15
15
  - **Multi-Agent Communication** - Claude instances talk to each other across projects
16
16
  - **@Mention Targeting** - Send messages to specific subagents or teams
@@ -126,7 +126,7 @@ HCOM_INSTANCE_HINTS="always update chat with progress" hcom open nice-subagent-b
126
126
  | `max_messages_per_delivery` | 50 | `HCOM_MAX_MESSAGES_PER_DELIVERY` | Messages delivered per batch |
127
127
  | `sender_name` | "bigboss" | `HCOM_SENDER_NAME` | Your name in chat |
128
128
  | `sender_emoji` | "🐳" | `HCOM_SENDER_EMOJI` | Your emoji icon |
129
- | `initial_prompt` | "Say hi" | `HCOM_INITIAL_PROMPT` | What new instances are told to do |
129
+ | `initial_prompt` | "Say hi in chat" | `HCOM_INITIAL_PROMPT` | What new instances are told to do |
130
130
  | `first_use_text` | "Essential, concise messages only" | `HCOM_FIRST_USE_TEXT` | Welcome message for instances |
131
131
  | `terminal_mode` | "new_window" | `HCOM_TERMINAL_MODE` | How to launch terminals ("new_window", "same_terminal", "show_commands") |
132
132
  | `terminal_command` | null | `HCOM_TERMINAL_COMMAND` | Custom terminal command (see Terminal Options) |
@@ -174,11 +174,11 @@ hcom adds hooks to your project directory's `.claude/settings.local.json`:
174
174
  - **Identity**: Each instance gets a unique name based on conversation UUID (e.g., "hovoa7")
175
175
  - **Persistence**: Names persist across `--resume` maintaining conversation context
176
176
  - **Status Detection**: Notification hook tracks permission requests and activity
177
- - **Agents**: When you run `hcom open researcher`, it loads an interactive claude session with a system prompt from `.claude/agents/researcher.md` (local) or `~/.claude/agents/researcher.md` (global)
177
+ - **Agents**: When you run `hcom open researcher`, it loads an interactive Claude session with a system prompt from `.claude/agents/researcher.md` (local) or `~/.claude/agents/researcher.md` (global). Agents can specify `model:` and `tools:` in YAML frontmatter
178
178
 
179
179
  ### Architecture
180
180
  - **Single conversation** - All instances share one global conversation
181
- - **Opt-in participation** - Only claude code instances launched with `hcom open` join the chat
181
+ - **Opt-in participation** - Only Claude Code instances launched with `hcom open` join the chat
182
182
  - **@-mention filtering** - Target messages to specific instances or teams
183
183
 
184
184
  ### File Structure
@@ -4,8 +4,8 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "hcom"
7
- version = "0.1.4"
8
- description = "Lightweight CLI tool for real-time messaging between Claude Code subagents using hooks"
7
+ version = "0.1.6"
8
+ description = "Lightweight CLI tool for real-time communication between Claude Code subagents using hooks"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.6"
11
11
  license = {text = "MIT"}
@@ -1,3 +1,3 @@
1
1
  """Claude Hook Comms - Real-time messaging between Claude Code agents."""
2
2
 
3
- __version__ = "0.1.3"
3
+ __version__ = "0.1.5"
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env python3
2
2
  """
3
3
  hcom - Claude Hook Comms
4
- A lightweight multi-agent communication system for claude code
4
+ Lightweight CLI tool for real-time communication between Claude Code subagents using hooks
5
5
  """
6
6
 
7
7
  import os
@@ -170,27 +170,22 @@ def get_config_value(key, default=None):
170
170
  return config.get(key, default)
171
171
 
172
172
  def get_hook_command():
173
- """Determine the best hook command approach based on paths"""
173
+ """Get hook command with silent fallback
174
+
175
+ Uses ${HCOM:-true} for clean paths, conditional for paths with spaces.
176
+ Both approaches exit silently (code 0) when not launched via 'hcom open'.
177
+ """
174
178
  python_path = sys.executable
175
179
  script_path = os.path.abspath(__file__)
176
180
 
177
- # Characters that cause issues in shell expansion
178
- problematic_chars = [' ', '`', '"', "'", '\\', '\n', ';', '&', '|', '(', ')', ':',
179
- '$', '*', '?', '[', ']', '{', '}', '!', '~', '<', '>']
180
-
181
- has_problematic_chars = any(char in python_path or char in script_path
182
- for char in problematic_chars)
183
-
184
- if has_problematic_chars:
185
- # Use direct paths with proper escaping
186
- # Escape backslashes first, then quotes
187
- escaped_python = python_path.replace('\\', '\\\\').replace('"', '\\"')
188
- escaped_script = script_path.replace('\\', '\\\\').replace('"', '\\"')
189
- return f'"{escaped_python}" "{escaped_script}"', {}
181
+ if ' ' in python_path or ' ' in script_path:
182
+ # Paths with spaces: use conditional check
183
+ escaped_python = shlex.quote(python_path)
184
+ escaped_script = shlex.quote(script_path)
185
+ return f'[ "${{HCOM_ACTIVE}}" = "1" ] && {escaped_python} {escaped_script} || true', {}
190
186
  else:
191
- # Use single clean env var
192
- env_vars = {'HCOM': f'{python_path} {script_path}'}
193
- return '$HCOM', env_vars
187
+ # Clean paths: use environment variable
188
+ return '${HCOM:-true}', {}
194
189
 
195
190
  def build_claude_env():
196
191
  """Build environment variables for Claude instances"""
@@ -206,9 +201,11 @@ def build_claude_env():
206
201
 
207
202
  env.update(config.get('env_overrides', {}))
208
203
 
209
- # Add hook-specific env vars if using that approach
210
- _, hook_env_vars = get_hook_command()
211
- env.update(hook_env_vars)
204
+ # Set HCOM only for clean paths (spaces handled differently)
205
+ python_path = sys.executable
206
+ script_path = os.path.abspath(__file__)
207
+ if ' ' not in python_path and ' ' not in script_path:
208
+ env['HCOM'] = f'{python_path} {script_path}'
212
209
 
213
210
  return env
214
211
 
@@ -335,6 +332,35 @@ def parse_open_args(args):
335
332
 
336
333
  return instances, prefix, claude_args
337
334
 
335
+ def extract_agent_config(content):
336
+ """Extract configuration from agent YAML frontmatter"""
337
+ if not content.startswith('---'):
338
+ return {}
339
+
340
+ # Find YAML section between --- markers
341
+ yaml_end = content.find('\n---', 3)
342
+ if yaml_end < 0:
343
+ return {} # No closing marker
344
+
345
+ yaml_section = content[3:yaml_end]
346
+ config = {}
347
+
348
+ # Extract model field
349
+ model_match = re.search(r'^model:\s*(.+)$', yaml_section, re.MULTILINE)
350
+ if model_match:
351
+ value = model_match.group(1).strip()
352
+ if value and value.lower() != 'inherit':
353
+ config['model'] = value
354
+
355
+ # Extract tools field
356
+ tools_match = re.search(r'^tools:\s*(.+)$', yaml_section, re.MULTILINE)
357
+ if tools_match:
358
+ value = tools_match.group(1).strip()
359
+ if value:
360
+ config['tools'] = value.replace(', ', ',')
361
+
362
+ return config
363
+
338
364
  def resolve_agent(name):
339
365
  """Resolve agent file by name
340
366
 
@@ -342,16 +368,17 @@ def resolve_agent(name):
342
368
  1. .claude/agents/{name}.md (local)
343
369
  2. ~/.claude/agents/{name}.md (global)
344
370
 
345
- Returns the content after stripping YAML frontmatter
371
+ Returns tuple: (content after stripping YAML frontmatter, config dict)
346
372
  """
347
373
  for base_path in [Path('.'), Path.home()]:
348
374
  agent_path = base_path / '.claude/agents' / f'{name}.md'
349
375
  if agent_path.exists():
350
376
  content = agent_path.read_text()
377
+ config = extract_agent_config(content)
351
378
  stripped = strip_frontmatter(content)
352
379
  if not stripped.strip():
353
380
  raise ValueError(format_error(f"Agent '{name}' has empty content", 'Check the agent file contains a system prompt'))
354
- return stripped
381
+ return stripped, config
355
382
 
356
383
  raise FileNotFoundError(format_error(f'Agent not found: {name}', 'Check available agents or create the agent file'))
357
384
 
@@ -393,15 +420,22 @@ def _remove_hcom_hooks_from_settings(settings):
393
420
 
394
421
  # Patterns to match any hcom hook command
395
422
  # - $HCOM post/stop/notify
423
+ # - ${HCOM:-...} post/stop/notify
424
+ # - [ "${HCOM_ACTIVE}" = "1" ] && ... hcom.py ... || true
396
425
  # - hcom post/stop/notify
426
+ # - uvx hcom post/stop/notify
397
427
  # - /path/to/hcom.py post/stop/notify
428
+ # - sh -c "[ ... ] && ... hcom ..."
398
429
  # - "/path with spaces/python" "/path with spaces/hcom.py" post/stop/notify
399
430
  # - '/path/to/python' '/path/to/hcom.py' post/stop/notify
400
431
  hcom_patterns = [
401
- r'\$HCOM\s+(post|stop|notify)\b', # Environment variable
432
+ r'\$\{?HCOM', # Environment variable (with or without braces)
433
+ r'\bHCOM_ACTIVE.*hcom\.py', # Conditional with HCOM_ACTIVE check
402
434
  r'\bhcom\s+(post|stop|notify)\b', # Direct hcom command
435
+ r'\buvx\s+hcom\s+(post|stop|notify)\b', # uvx hcom command
403
436
  r'hcom\.py["\']?\s+(post|stop|notify)\b', # hcom.py with optional quote
404
437
  r'["\'][^"\']*hcom\.py["\']?\s+(post|stop|notify)\b', # Quoted path with hcom.py
438
+ r'sh\s+-c.*hcom', # Shell wrapper with hcom
405
439
  ]
406
440
  compiled_patterns = [re.compile(pattern) for pattern in hcom_patterns]
407
441
 
@@ -452,7 +486,7 @@ def format_warning(message):
452
486
  """Format warning message consistently"""
453
487
  return f"Warning: {message}"
454
488
 
455
- def build_claude_command(agent_content=None, claude_args=None, initial_prompt="Say hi in chat"):
489
+ def build_claude_command(agent_content=None, claude_args=None, initial_prompt="Say hi in chat", model=None, tools=None):
456
490
  """Build Claude command with proper argument handling
457
491
 
458
492
  Returns tuple: (command_string, temp_file_path_or_none)
@@ -461,6 +495,27 @@ def build_claude_command(agent_content=None, claude_args=None, initial_prompt="S
461
495
  cmd_parts = ['claude']
462
496
  temp_file_path = None
463
497
 
498
+ # Add model if specified and not already in claude_args
499
+ if model:
500
+ # Check if model already specified in args (more concise)
501
+ has_model = claude_args and any(
502
+ arg in ['--model', '-m'] or
503
+ arg.startswith(('--model=', '-m='))
504
+ for arg in claude_args
505
+ )
506
+ if not has_model:
507
+ cmd_parts.extend(['--model', model])
508
+
509
+ # Add allowed tools if specified and not already in claude_args
510
+ if tools:
511
+ has_tools = claude_args and any(
512
+ arg in ['--allowedTools', '--allowed-tools'] or
513
+ arg.startswith(('--allowedTools=', '--allowed-tools='))
514
+ for arg in claude_args
515
+ )
516
+ if not has_tools:
517
+ cmd_parts.extend(['--allowedTools', tools])
518
+
464
519
  if claude_args:
465
520
  for arg in claude_args:
466
521
  cmd_parts.append(shlex.quote(arg))
@@ -662,7 +717,7 @@ def setup_hooks():
662
717
  if hcom_send_permission not in settings['permissions']['allow']:
663
718
  settings['permissions']['allow'].append(hcom_send_permission)
664
719
 
665
- # Get the hook command approach (env vars or direct paths based on spaces)
720
+ # Get the hook command template
666
721
  hook_cmd_base, _ = get_hook_command()
667
722
 
668
723
  # Add PostToolUse hook
@@ -718,16 +773,36 @@ def get_archive_timestamp():
718
773
  return datetime.now().strftime("%Y%m%d-%H%M%S")
719
774
 
720
775
  def get_conversation_uuid(transcript_path):
721
- """Get conversation UUID from transcript"""
776
+ """Get conversation UUID from transcript
777
+
778
+ For resumed sessions, the first line may be a summary with a different leafUuid.
779
+ We need to find the first user entry which contains the stable conversation UUID.
780
+ """
722
781
  try:
723
782
  if not transcript_path or not os.path.exists(transcript_path):
724
783
  return None
725
784
 
785
+ # First, try to find the UUID from the first user entry
786
+ with open(transcript_path, 'r') as f:
787
+ for line in f:
788
+ line = line.strip()
789
+ if not line:
790
+ continue
791
+ try:
792
+ entry = json.loads(line)
793
+ # Look for first user entry with a UUID - this is the stable identifier
794
+ if entry.get('type') == 'user' and entry.get('uuid'):
795
+ return entry.get('uuid')
796
+ except json.JSONDecodeError:
797
+ continue
798
+
799
+ # Fallback: If no user entry found, try the first line (original behavior)
726
800
  with open(transcript_path, 'r') as f:
727
801
  first_line = f.readline().strip()
728
802
  if first_line:
729
803
  entry = json.loads(first_line)
730
- return entry.get('uuid')
804
+ # Try both 'uuid' and 'leafUuid' fields
805
+ return entry.get('uuid') or entry.get('leafUuid')
731
806
  except Exception:
732
807
  pass
733
808
  return None
@@ -1119,7 +1194,8 @@ def migrate_instance_name_if_needed(instance_name, conversation_uuid, transcript
1119
1194
  if instance_name.endswith("claude") and conversation_uuid:
1120
1195
  new_instance = get_display_name(transcript_path)
1121
1196
  if new_instance != instance_name and not new_instance.endswith("claude"):
1122
- # Migrate from fallback name to UUID-based name
1197
+ # Always return the new name if we can generate it
1198
+ # Migration of data only happens if old name exists
1123
1199
  pos_file = get_hcom_dir() / "hcom.json"
1124
1200
  positions = load_positions(pos_file)
1125
1201
  if instance_name in positions:
@@ -1128,8 +1204,7 @@ def migrate_instance_name_if_needed(instance_name, conversation_uuid, transcript
1128
1204
  # Update the conversation UUID in the migrated data
1129
1205
  positions[new_instance]["conversation_uuid"] = conversation_uuid
1130
1206
  atomic_write(pos_file, json.dumps(positions, indent=2))
1131
- # Instance name migrated
1132
- return new_instance
1207
+ return new_instance
1133
1208
  return instance_name
1134
1209
 
1135
1210
  def update_instance_position(instance_name, update_fields):
@@ -1282,11 +1357,16 @@ def cmd_open(*args):
1282
1357
  else:
1283
1358
  # Agent instance
1284
1359
  try:
1285
- agent_content = resolve_agent(instance_type)
1360
+ agent_content, agent_config = resolve_agent(instance_type)
1361
+ # Use agent's model and tools if specified and not overridden in claude_args
1362
+ agent_model = agent_config.get('model')
1363
+ agent_tools = agent_config.get('tools')
1286
1364
  claude_cmd, temp_file = build_claude_command(
1287
1365
  agent_content=agent_content,
1288
1366
  claude_args=claude_args,
1289
- initial_prompt=initial_prompt
1367
+ initial_prompt=initial_prompt,
1368
+ model=agent_model,
1369
+ tools=agent_tools
1290
1370
  )
1291
1371
  if temp_file:
1292
1372
  temp_files_to_cleanup.append(temp_file)
@@ -1746,12 +1826,9 @@ def handle_hook_post():
1746
1826
  # Migrate instance name if needed (from fallback to UUID-based)
1747
1827
  instance_name = migrate_instance_name_if_needed(instance_name, conversation_uuid, transcript_path)
1748
1828
 
1749
- # Initialize instance if needed
1750
- if not instance_name.endswith("claude") or conversation_uuid:
1751
- initialize_instance_in_position_file(instance_name, conversation_uuid)
1752
-
1753
- # Update instance position
1754
- update_instance_position(instance_name, {
1829
+ initialize_instance_in_position_file(instance_name, conversation_uuid)
1830
+
1831
+ update_instance_position(instance_name, {
1755
1832
  'last_tool': int(time.time()),
1756
1833
  'last_tool_name': hook_data.get('tool_name', 'unknown'),
1757
1834
  'session_id': hook_data.get('session_id', ''),
@@ -1788,8 +1865,7 @@ def handle_hook_post():
1788
1865
  elif message and message[-1] in '"\'':
1789
1866
  message = message[:-1]
1790
1867
 
1791
- if message and not instance_name.endswith("claude"):
1792
- # Validate message
1868
+ if message:
1793
1869
  error = validate_message(message)
1794
1870
  if error:
1795
1871
  output = {"reason": f"❌ {error}"}
@@ -1799,27 +1875,25 @@ def handle_hook_post():
1799
1875
  send_message(instance_name, message)
1800
1876
  sent_reason = "✓ Sent"
1801
1877
 
1802
- # Check for pending messages to deliver
1803
- if not instance_name.endswith("claude"):
1804
- messages = get_new_messages(instance_name)
1805
-
1806
- if messages and sent_reason:
1807
- # Both sent and received
1808
- reason = f"{sent_reason} | {format_hook_messages(messages, instance_name)}"
1809
- output = {"decision": HOOK_DECISION_BLOCK, "reason": reason}
1810
- print(json.dumps(output, ensure_ascii=False), file=sys.stderr)
1811
- sys.exit(EXIT_BLOCK)
1812
- elif messages:
1813
- # Just received
1814
- reason = format_hook_messages(messages, instance_name)
1815
- output = {"decision": HOOK_DECISION_BLOCK, "reason": reason}
1816
- print(json.dumps(output, ensure_ascii=False), file=sys.stderr)
1817
- sys.exit(EXIT_BLOCK)
1818
- elif sent_reason:
1819
- # Just sent
1820
- output = {"reason": sent_reason}
1821
- print(json.dumps(output, ensure_ascii=False), file=sys.stderr)
1822
- sys.exit(EXIT_BLOCK)
1878
+ messages = get_new_messages(instance_name)
1879
+
1880
+ if messages and sent_reason:
1881
+ # Both sent and received
1882
+ reason = f"{sent_reason} | {format_hook_messages(messages, instance_name)}"
1883
+ output = {"decision": HOOK_DECISION_BLOCK, "reason": reason}
1884
+ print(json.dumps(output, ensure_ascii=False), file=sys.stderr)
1885
+ sys.exit(EXIT_BLOCK)
1886
+ elif messages:
1887
+ # Just received
1888
+ reason = format_hook_messages(messages, instance_name)
1889
+ output = {"decision": HOOK_DECISION_BLOCK, "reason": reason}
1890
+ print(json.dumps(output, ensure_ascii=False), file=sys.stderr)
1891
+ sys.exit(EXIT_BLOCK)
1892
+ elif sent_reason:
1893
+ # Just sent
1894
+ output = {"reason": sent_reason}
1895
+ print(json.dumps(output, ensure_ascii=False), file=sys.stderr)
1896
+ sys.exit(EXIT_BLOCK)
1823
1897
 
1824
1898
  except Exception:
1825
1899
  pass
@@ -1839,9 +1913,6 @@ def handle_hook_stop():
1839
1913
  instance_name = get_display_name(transcript_path) if transcript_path else f"{Path.cwd().name[:2].lower()}claude"
1840
1914
  conversation_uuid = get_conversation_uuid(transcript_path)
1841
1915
 
1842
- if instance_name.endswith("claude") and not conversation_uuid:
1843
- sys.exit(EXIT_SUCCESS)
1844
-
1845
1916
  # Initialize instance if needed
1846
1917
  initialize_instance_in_position_file(instance_name, conversation_uuid)
1847
1918
 
@@ -1906,9 +1977,6 @@ def handle_hook_notification():
1906
1977
  instance_name = get_display_name(transcript_path) if transcript_path else f"{Path.cwd().name[:2].lower()}claude"
1907
1978
  conversation_uuid = get_conversation_uuid(transcript_path)
1908
1979
 
1909
- if instance_name.endswith("claude") and not conversation_uuid:
1910
- sys.exit(EXIT_SUCCESS)
1911
-
1912
1980
  # Initialize instance if needed
1913
1981
  initialize_instance_in_position_file(instance_name, conversation_uuid)
1914
1982
 
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hcom
3
- Version: 0.1.4
4
- Summary: Lightweight CLI tool for real-time messaging between Claude Code subagents using hooks
3
+ Version: 0.1.6
4
+ Summary: Lightweight CLI tool for real-time communication between Claude Code subagents using hooks
5
5
  Author-email: aannoo <your@email.com>
6
6
  License: MIT
7
7
  Project-URL: Homepage, https://github.com/aannoo/claude-hook-comms
@@ -26,9 +26,9 @@ Classifier: Topic :: Communications
26
26
  Requires-Python: >=3.6
27
27
  Description-Content-Type: text/markdown
28
28
 
29
- # Claude Code Hook Comms
29
+ # hcom - Claude Hook Comms
30
30
 
31
- Lightweight CLI tool for real-time communication between claude code [subagents](https://docs.anthropic.com/en/docs/claude-code/sub-agents) using [hooks](https://docs.anthropic.com/en/docs/claude-code/hooks).
31
+ Lightweight CLI tool for real-time communication between Claude Code [subagents](https://docs.anthropic.com/en/docs/claude-code/sub-agents) using [hooks](https://docs.anthropic.com/en/docs/claude-code/hooks).
32
32
 
33
33
  ## 🦆 What It Does
34
34
 
@@ -38,7 +38,7 @@ Creates a group chat where you and multiple interactive Claude Code subagents ca
38
38
 
39
39
  ## 🦷 Features
40
40
 
41
- - **Multi-Terminal Launch** - Launch claude code subagents in new terminals
41
+ - **Multi-Terminal Launch** - Launch Claude Code subagents in new terminals
42
42
  - **Live Dashboard** - Real-time monitoring of all instances
43
43
  - **Multi-Agent Communication** - Claude instances talk to each other across projects
44
44
  - **@Mention Targeting** - Send messages to specific subagents or teams
@@ -154,7 +154,7 @@ HCOM_INSTANCE_HINTS="always update chat with progress" hcom open nice-subagent-b
154
154
  | `max_messages_per_delivery` | 50 | `HCOM_MAX_MESSAGES_PER_DELIVERY` | Messages delivered per batch |
155
155
  | `sender_name` | "bigboss" | `HCOM_SENDER_NAME` | Your name in chat |
156
156
  | `sender_emoji` | "🐳" | `HCOM_SENDER_EMOJI` | Your emoji icon |
157
- | `initial_prompt` | "Say hi" | `HCOM_INITIAL_PROMPT` | What new instances are told to do |
157
+ | `initial_prompt` | "Say hi in chat" | `HCOM_INITIAL_PROMPT` | What new instances are told to do |
158
158
  | `first_use_text` | "Essential, concise messages only" | `HCOM_FIRST_USE_TEXT` | Welcome message for instances |
159
159
  | `terminal_mode` | "new_window" | `HCOM_TERMINAL_MODE` | How to launch terminals ("new_window", "same_terminal", "show_commands") |
160
160
  | `terminal_command` | null | `HCOM_TERMINAL_COMMAND` | Custom terminal command (see Terminal Options) |
@@ -202,11 +202,11 @@ hcom adds hooks to your project directory's `.claude/settings.local.json`:
202
202
  - **Identity**: Each instance gets a unique name based on conversation UUID (e.g., "hovoa7")
203
203
  - **Persistence**: Names persist across `--resume` maintaining conversation context
204
204
  - **Status Detection**: Notification hook tracks permission requests and activity
205
- - **Agents**: When you run `hcom open researcher`, it loads an interactive claude session with a system prompt from `.claude/agents/researcher.md` (local) or `~/.claude/agents/researcher.md` (global)
205
+ - **Agents**: When you run `hcom open researcher`, it loads an interactive Claude session with a system prompt from `.claude/agents/researcher.md` (local) or `~/.claude/agents/researcher.md` (global). Agents can specify `model:` and `tools:` in YAML frontmatter
206
206
 
207
207
  ### Architecture
208
208
  - **Single conversation** - All instances share one global conversation
209
- - **Opt-in participation** - Only claude code instances launched with `hcom open` join the chat
209
+ - **Opt-in participation** - Only Claude Code instances launched with `hcom open` join the chat
210
210
  - **@-mention filtering** - Target messages to specific instances or teams
211
211
 
212
212
  ### File Structure
File without changes
File without changes
File without changes