Skip to content

Custom agent definitions (.claude/agents/) are silently ignored for team agents #30703

Closed as not planned

Description

@marcoabreu

Summary

When a custom agent definition (.claude/agents/<name>.md) is used to spawn a team agent (via the Agent tool with team_name parameter), all frontmatter fields and the markdown body (system prompt) are silently ignored. Only model and agent_type (in SubagentStart/SubagentStop hooks) work correctly.

The same custom agent definitions work fully when spawned as pure subagents (without team_name).

Reproduction

  1. Create .claude/agents/my-agent.md:
---
name: my-agent
description: Test agent with baked-in identity.
model: opus
hooks:
  PreToolUse:
    - matcher: ""
      hooks:
        - type: command
          command: echo "hook fired"
skills:
  - my-skill
disallowedTools: Write, Edit
---

# You are: My Agent

You have a specific identity and instructions baked in.
  1. Spawn as pure subagent (works correctly):
Agent(subagent_type="my-agent", prompt="What is your role?")

→ Agent receives the markdown body as system prompt, hooks fire, model is applied.

  1. Spawn as team agent (broken):
Agent(subagent_type="my-agent", team_name="my-team", name="team-agent" prompt="What is your role?")

→ Agent has NO custom system prompt. Only project-wide rules (.claude/rules/) and CLAUDE.md files are loaded. Agent cannot identify itself.

What is silently ignored for team agents

Feature Pure subagent Team agent
System prompt (markdown body) ✅ Works ✅ Works
skills frontmatter ✅ Works ❌ Silently ignored (known: #29441 / #24780)
disallowedTools frontmatter ✅ Works ✅ Works
Frontmatter hooks ✅ Works ❌ Silently ignored
model frontmatter ✅ Works ✅ Works
agent_type in SubagentStart/Stop ✅ Works ✅ Works

Impact

This makes custom agent definitions nearly useless for team-based workflows. Teams cannot:

  • Bake role identity into agents (must use spawn prompt instead)
  • Enforce tool restrictions via disallowedTools
  • Attach lifecycle hooks to specific agent types
  • Preload skills into team agents

The silent failure is particularly problematic — there are no warnings or errors. Users may believe their agent definitions are being applied when they are not.

Environment

  • Claude Code version: 2.1.68
  • Platform: macOS (Darwin 24.5.0, arm64)
  • Agent teams enabled via CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1

Related issues

Activity

  1. github-actions commented on Mar 4, 2026

    @github-actions

    Found 2 possible duplicate issues:

    1. [BUG] Bug: Teammates do NOT load skills despite documentation stating they do #24780
    2. Custom agents lose file tools when spawned with team_name #25608

    This issue will be automatically closed as a duplicate in 3 days.

    • If your issue is a duplicate, please close it and 👍 the existing issue instead
    • To prevent auto-closure, add a comment or 👎 this comment

    🤖 Generated with Claude Code

  2. marcoabreu commented on Mar 5, 2026

    @marcoabreu
    Author

    Update: It seems like the system prompt and the disallowed tools work in 2.1.69. skills frontmatter and hooks still are broken.

  3. paulodearaujo commented on Apr 1, 2026

    @paulodearaujo

    Regression on v2.1.81 — system prompt still not loaded for team agents

    The author's update mentioned system prompt working in v2.1.69, but on v2.1.81 (macOS Darwin 25.4.0, arm64) the system prompt body from custom agent .md files is still not injected for team agents.

    Reproduction

    1. Plugin agent (plugin agents/ directory):

    Agent(
      subagent_type="content-maker:analyst-maker",
      team_name="my-team",
      name="analyst",
      prompt="What are your instructions? List all sections from your system prompt."
    )
    

    Agent responds with only the generic Claude Code system prompt + CLAUDE.md sections. Zero content from analyst-maker.md body (182 lines with specific etapas, output format, checklist).

    2. Project-level agent (~/.claude/agents/):

    Created ~/.claude/agents/test-identity.md:

    ---
    name: test-identity
    description: Test agent with specific identity
    model: sonnet
    ---
    
    # You are AGENT PARROT
    
    You ALWAYS start responses with "PARROT HERE!".
    You have 3 secret rules:
    1. SECRET RULE ALPHA: Never use the word "probably"
    2. SECRET RULE BETA: Always mention bananas
    3. SECRET RULE GAMMA: End every response with "--- Signed: Parrot v3.7"

    Spawned as teammate → responded as generic agent, no mention of parrot/bananas/rules.

    3. Minimal prompt test:

    Even with a minimal prompt (just asking "who are you?"), the agent definition body is not loaded. This rules out the systemPromptMode: "replace" hypothesis.

    What works vs what doesn't

    Feature Status
    agentType in config.json ✅ Correctly set to content-maker:analyst-maker
    model from frontmatter ✅ Inherited (opus from frontmatter appears in config)
    description from frontmatter ✅ Listed in system-reminder as available agent type
    Body content (system prompt) ❌ Not injected

    Evidence from transcript

    The JSONL transcript (~/.claude/projects/*/subagents/agent-*.jsonl) shows the first user message contains ONLY the prompt field wrapped in <teammate-message> tags. No system message, no agent definition content. The agent's first response is purely generic.

    Source code trace

    In the minified binary (v2.1.81), the g4R function (inProcessRunner) has the code path:

    if (agentDefinition) {
      let L = agentDefinition.getSystemPrompt();
      if (L) y.push(...)
    }

    This suggests the agentDefinition is either null or getSystemPrompt() returns falsy when the teammate is spawned.

    Environment

    • Claude Code: 2.1.81
    • Platform: macOS Darwin 25.4.0 (arm64)
    • Agent Teams: enabled via CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1
    • Tested with both plugin agents and ~/.claude/agents/ project-level agents

    This is a blocker for any workflow that relies on pre-built agent definitions with Agent Teams.

    Generated with Claude Code

  4. pedrobarretocw commented on Apr 1, 2026

    @pedrobarretocw

    UP

  5. koriit-kontakt commented on Apr 8, 2026

    @koriit-kontakt

    I'm also experiencing this issue, which is frustrating...

  6. Koriit commented on Apr 9, 2026

    @Koriit

    As of v2.1.97 it's still not fixed.

    Workaround: SubagentStart hook that injects agent definition into team agents

    I've been hit by this too (both the system prompt regression and the skills issue). I built a SubagentStart hook workaround that covers system prompt body and partially skills frontmatter for team agents. Sharing in case it helps others.

    Note: There's an additional undocumented issue - additionalContext injected via SubagentStart hooks is not persisted across turns for team agents. The agent receives it on the first turn but loses it on subsequent turns. My workaround addresses this by re-injecting on every turn.

    Note2: In the leaked source files I noticed that for teammates the agent.type is replaced with agent name which may be why proper files are not loaded. This problem is also present in the hook input, which is why I had to resort to reading transcript files.

    How it works

    1. The SubagentStart hook fires on every teammate turn
    2. It reads transcript_path from the hook input and scans the JSONL for the most recent Agent tool_use where input.name or input.subagent_type matches the hook's agent_type - and where input.team_name is set (teammates only; regular subagents work fine)
    3. Uses input.subagent_type from the transcript to locate the correct .md file (since agent_type in the hook payload contains the agent's display name for teammates, not the qualified plugin:agent type). Should work for plugins (official and custom), local agents, and user agents.
    4. Parses the skills: list from YAML frontmatter and generates a <LOAD-DEPENDENCY> block instructing the agent to load them
    5. Strips frontmatter, wraps the body + skill instructions in <system-reminder> tags, and emits it as additionalContext

    What it does NOT cover

    • Skills loading is best-effort: the <LOAD-DEPENDENCY> instruction tells the agent to proactively load its skills, but it's a hint - not a guarantee.
    • Per-agent hooks frontmatter: the SubagentStart hook can only inject context, not register new hooks dynamically. Global hooks only.
    • True system prompt placement: additionalContext is injected as context, not as the actual system prompt. Behavior is close enough for most agents but not identical.

    Key design decisions

    • Transcript-based resolution: the hook reads the session transcript to find which Agent tool_use spawned this teammate. This is necessary because agent_type in the hook payload is the agent's display name (e.g., "pr-opener"), not the qualified type (e.g., "pull-request:pr-opener") needed to locate the .md file.
    • Re-inject every turn: I intentionally fire on every turn because additionalContext is not persisted across teammate turns - without re-injection the agent loses its definition after the first turn. I'm unsure whether SubagentStart firing on every teammate turn is intended behavior or a separate bug, but in my case it's actually saving me - without it, the workaround would only work on the first turn.
    • Teammate-only: the hook skips injection when team_name is absent in the transcript tool_use, since regular subagents receive their definition correctly.
    • Retry on first spawn: the transcript entry may not be flushed when the hook first fires, so it retries up to 3 times with 500ms delay.

    Implementation

    The hook is a single Python script (stdlib only) installed as a plugin.

    hooks/hooks.json

    {
      "hooks": {
        "SubagentStart": [
          {
            "hooks": [
              {
                "type": "command",
                "command": "${CLAUDE_PLUGIN_ROOT}/hooks/inject-agent-def"
              }
            ]
          }
        ]
      }
    }

    hooks/inject-agent-def (remeber to do chmod +x)

    #!/usr/bin/env python3
    """
    Workaround for anthropics/claude-code#30703
    Injects agent definition body as additionalContext on SubagentStart.
    
    Resolution flow:
      1. Read agent_type + transcript_path from stdin JSON
      2. Scan transcript JSONL for most recent Agent tool_use where
         input.team_name is set (teammate spawn only)  AND
         input.name == agent_type  OR  input.subagent_type == agent_type
      3. If not found or older than 30s → exit 0 (no injection)
      4. Use input.subagent_type from that entry to locate the .md file
      5. Strip frontmatter, emit additionalContext JSON
    
    Only applies to teammate spawns (team_name present in tool_use input).
    Regular subagents receive their definition correctly from Claude Code.
    No fallback if transcript_path is absent — without it we risk
    injecting on every teammate turn (Claude Code bug).
    
    Dependencies: python3 stdlib, claude CLI (for marketplace list)
    Debug: set CLAUDE_HOOKS_DEBUG_FILE=/path/to/file
    """
    
    import json
    import os
    import sys
    import time
    import subprocess
    from pathlib import Path
    from datetime import datetime
    SCRIPT_NAME = os.path.basename(sys.argv[0])
    CORR_ID = f'{os.getpid():05d}'
    DEBUG_FILE = os.environ.get('CLAUDE_HOOKS_DEBUG_FILE', '')
    
    
    def dbg(msg):
        if not DEBUG_FILE:
            return
        ts = datetime.now().strftime('%Y-%m-%dT%H:%M:%S')
        line = f'[{ts}] [{SCRIPT_NAME}] [{CORR_ID}] {msg}\n'
        try:
            with open(DEBUG_FILE, 'a') as f:
                f.write(line)
        except Exception:
            pass
    
    
    def strip_frontmatter(content):
        """Strip YAML frontmatter (between first and second ---), return body."""
        lines = content.splitlines(keepends=True)
        dashes_seen = 0
        result_lines = []
        for line in lines:
            if line.rstrip('\n\r') == '---':
                dashes_seen += 1
                continue
            if dashes_seen >= 2:
                result_lines.append(line)
        return ''.join(result_lines).rstrip('\n')
    
    
    def extract_skills(content):
        """Extract the skills list from YAML frontmatter. Returns list of skill strings."""
        lines = content.splitlines()
        dashes_seen = 0
        in_skills = False
        skills = []
        for line in lines:
            if line.rstrip() == '---':
                dashes_seen += 1
                if dashes_seen == 2:
                    break
                continue
            if dashes_seen == 0:
                continue
            if line.startswith('skills:'):
                in_skills = True
                continue
            if in_skills:
                stripped = line.strip()
                if stripped.startswith('- '):
                    skills.append(stripped[2:].strip())
                elif line and not line[0].isspace():
                    in_skills = False  # new top-level key, skills list ended
        return skills
    
    
    def get_marketplace_locations():
        """Run claude plugins marketplace list --json, return list of installLocation strings."""
        try:
            result = subprocess.run(
                ['claude', 'plugins', 'marketplace', 'list', '--json'],
                capture_output=True, text=True, timeout=10
            )
            data = json.loads(result.stdout)
            locations = []
            for entry in data:
                loc = entry.get('installLocation')
                if loc and loc != 'null':
                    locations.append(loc)
            return locations
        except Exception as e:
            dbg(f'get_marketplace_locations error: {e}')
            return []
    
    
    def find_agent_file(agent_type, cwd):
        """Locate the .md file for agent_type. Returns path string or None."""
        if ':' in agent_type:
            # Plugin branch: "pluginName:agentName" or "pluginName:ns:agentName"
            plugin_name = agent_type.split(':')[0]
            agent_name = agent_type.rsplit(':', 1)[1]
            dbg(f"plugin branch: plugin='{plugin_name}' agent='{agent_name}'")
    
            # Search marketplace install locations
            locations = get_marketplace_locations()
            for install_loc in locations:
                f = os.path.join(install_loc, 'plugins', plugin_name, 'agents', f'{agent_name}.md')
                dbg(f'checking marketplace path: {f}')
                if os.path.isfile(f):
                    dbg(f'found in marketplace: {f}')
                    return f
    
            # Cache fallback — glob, sort, take last
            cache_dir = Path.home() / '.claude' / 'plugins' / 'cache'
            pattern = f'*/{plugin_name}/*/agents/{agent_name}.md'
            matches = sorted(cache_dir.glob(pattern))
            if matches:
                found = str(matches[-1])
                dbg(f'found in cache: {found}')
                return found
    
        else:
            # Local branch: project .claude/agents/ then user ~/.claude/agents/
            dbg(f"local branch: agent_type='{agent_type}'")
    
            f = os.path.join(cwd, '.claude', 'agents', f'{agent_type}.md')
            dbg(f'checking project path: {f}')
            if os.path.isfile(f):
                dbg(f'found in project: {f}')
                return f
    
            f = str(Path.home() / '.claude' / 'agents' / f'{agent_type}.md')
            dbg(f'checking user path: {f}')
            if os.path.isfile(f):
                dbg(f'found in user dir: {f}')
                return f
    
        return None
    
    
    def find_in_transcript(transcript_path, agent_type):
        """
        Scan transcript JSONL for the most recent Agent tool_use matching agent_type.
        Returns (subagent_type_str, timestamp_str) or (None, None).
        Returns (None, ts_str) if found but stale.
        """
        last_match = None  # (subagent_type, timestamp_str)
    
        try:
            with open(transcript_path, 'r', encoding='utf-8') as f:
                for line in f:
                    line = line.strip()
                    if not line:
                        continue
                    try:
                        entry = json.loads(line)
                    except Exception:
                        continue
    
                    if entry.get('type') != 'assistant':
                        continue
    
                    msg = entry.get('message', entry)
                    content = msg.get('content', [])
                    if not isinstance(content, list):
                        continue
    
                    for block in content:
                        if not isinstance(block, dict):
                            continue
                        if block.get('type') != 'tool_use':
                            continue
                        if block.get('name') != 'Agent':
                            continue
    
                        inp = block.get('input', {})
                        name_match = agent_type == inp.get('name') or agent_type == inp.get('subagent_type')
                        if name_match and not inp.get('team_name'):
                            dbg(f"skipping tool_use: agent_type='{agent_type}' matched but team_name not set — not a teammate spawn")
                            continue
                        # Only inject for teammate spawns (team_name set).
                        # Regular subagents get their definition injected correctly by Claude Code.
                        if inp.get('team_name') and name_match:
                            resolved = inp.get('subagent_type') or inp.get('name')
                            ts = entry.get('timestamp')
                            last_match = (resolved, ts)
    
        except Exception as e:
            dbg(f'find_in_transcript error: {e}')
            return (None, None)
    
        if last_match is None:
            return (None, None)
    
        return last_match
    
    
    def main():
        raw = sys.stdin.read()
        dbg(f'INPUT: {raw}')
    
        try:
            data = json.loads(raw)
        except Exception as e:
            dbg(f'failed to parse stdin JSON: {e}')
            return
    
        agent_type = data.get('agent_type') or ''
        cwd = data.get('cwd') or ''
        transcript_path = data.get('transcript_path') or ''
    
        dbg(f"START agent_type='{agent_type}' cwd='{cwd}' transcript_path='{transcript_path}'")
    
        if not agent_type:
            dbg('empty agent_type, skipping')
            return
    
        if not transcript_path:
            dbg('no transcript_path, skipping')
            return
    
        # Retry when not found — transcript may not be flushed yet at hook fire time.
        RETRIES = 3
        RETRY_DELAY = 0.5
        resolved_type, ts_str = None, None
        for attempt in range(RETRIES):
            resolved_type, ts_str = find_in_transcript(transcript_path, agent_type)
            if resolved_type is not None:
                break
            if attempt < RETRIES - 1:
                dbg(f'no match on attempt {attempt + 1}/{RETRIES}, retrying in {RETRY_DELAY}s')
                time.sleep(RETRY_DELAY)
    
        if resolved_type is None:
            dbg(f'no matching teammate spawn found in transcript, skipping')
            return
    
        dbg(f"transcript resolved: agent_type='{agent_type}' → resolved='{resolved_type}' ts='{ts_str}'")
    
        agent_file = find_agent_file(resolved_type, cwd)
        if not agent_file:
            dbg(f"no agent file found for resolved='{resolved_type}', exiting")
            return
    
        dbg(f'using agent file: {agent_file}')
    
        try:
            with open(agent_file, 'r', encoding='utf-8') as f:
                file_content = f.read()
        except Exception as e:
            dbg(f'failed to read agent file: {e}')
            return
    
        body = strip_frontmatter(file_content)
        if not body:
            dbg('body is empty (frontmatter only?), exiting')
            return
    
        skills = extract_skills(file_content)
        if skills:
            skill_lines = '\n'.join(f'- `{s}`' for s in skills)
            load_dep = (
                f'<LOAD-DEPENDENCY>\n'
                f'Before starting, you MUST carefully load the following skills if not already loaded:\n'
                f'{skill_lines}\n'
                f'Do not proceed without them for ANYTHING even simple tasks or questions.\n'
                f'</LOAD-DEPENDENCY>\n'
            )
            dbg(f'injecting {len(skills)} skills: {", ".join(skills)}')
        else:
            load_dep = ''
    
        wrapped = f'<system-reminder>\n{body}\n\n{load_dep}</system-reminder>' if load_dep else f'<system-reminder>\n{body}\n</system-reminder>'
        dbg(f'injecting definition ({len(body.splitlines())} lines)')
    
        output = json.dumps({
            'hookSpecificOutput': {
                'hookEventName': 'SubagentStart',
                'additionalContext': wrapped
            }
        })
        dbg(f'OUTPUT: {output}')
        sys.stdout.write(output)
    
    
    try:
        main()
    except Exception as e:
        if DEBUG_FILE:
            dbg(f'unhandled exception: {e}')
    sys.exit(0)
  7. Leu-s commented on Apr 10, 2026

    @Leu-s

    Confirming still reproduces on v2.1.101 (macOS Darwin 24.6, CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1), four versions after @Koriit's v2.1.97 confirmation.

    Adding one data point to the silently-ignored-frontmatter list: memory:. Declaring memory: project in a teammate's .claude/agents/*.md has no effect — the .claude/agent-memory/<agent-name>/MEMORY.md file is simply not loaded into the teammate's system prompt. For the same definition spawned as a pure (non-team) subagent on the same machine, memory: loads correctly. Extending the OP's table:

    Feature Pure subagent Team agent
    memory: frontmatter ✅ Works ❌ Silently ignored (new)

    I also want to independently confirm @Koriit's finding that hook-injected additionalContext does not persist across turns for teammates. We hit the same quirk building a SubagentStart-hook workaround for this issue, and independently arrived at the same fix (re-inject on a Stop hook every turn). That two separate implementations converged on the same workaround is a strong signal it's real behavior, not an implementation artifact — worth surfacing as a first-class documented behavior or fixing.

    Longer-form context and a production use case is in my comment on the #24316 feature request thread. Happy to provide more reproduction detail if useful.

  8. github-actions commented on May 24, 2026

    @github-actions

    Closing for now — inactive for too long. Please open a new issue if this is still relevant.

  9. olarcher commented on May 26, 2026

    @olarcher

    Update from a fresh local POC on Claude Code 2.1.150:

    I can no longer reproduce the full original issue. In my test, custom .claude/agents/*.md definitions are now applied to teammate agents:

    • Agent body/system prompt markers: work for teammates
    • memory: project: works for teammates
    • skills: frontmatter: works for teammates
    • model: frontmatter: works; my team lead ran Opus while the custom teammate ran Sonnet

    The remaining thing I can still reproduce is narrower: per-agent hooks: frontmatter is ignored for teammate agents.

    Minimal setup:

    ---
    name: repro-team-identity
    description: Reproduction agent for teammate hook loading
    model: sonnet
    memory: project
    hooks:
      PreToolUse:
        - matcher: "Read"
          hooks:
            - type: command
              command: python3 scripts/record-agent-hook.py
    ---

    The agent is asked to run Read on README.md.

    Observed behavior:

    • Spawned as a normal subagent: hook fires and writes pure.hook-events.jsonl
    • Spawned with team_name / name: teammate runs Read, but no hook event is written
    • The teammate transcript contains the expected agent body and memory markers, so this looks specific to hooks: frontmatter, not custom-agent loading overall

    Corrected report from the POC:

    {
      "reproductions": {
        "system_prompt_body": false,
        "memory_frontmatter": false,
        "pre_tool_hook_frontmatter": true
      },
      "still_reproduces": true,
      "team_markers": {
        "identity_marker": true,
        "greeting_marker": true,
        "memory_marker": true,
        "tool_policy_marker": true
      },
      "team_hook_fired": false
    }

    So from my current test, #30703 appears mostly fixed in 2.1.150. The remaining actionable issue is that teammate agents silently ignore per-agent hooks: frontmatter.

  10. Koriit commented on May 26, 2026

    @Koriit

    @olarcher thanks for posting, I wouldn't notice otherwise. I also confirm your findings. 🙌

  11. jackalai commented on Jun 11, 2026

    @jackalai

    Cross-linking a related feature request I just filed: #67424 — proposes opt-in AgentDefinition.projectDir / inheritProjectSettings so subagent sessions can load the parent project's .claude/settings.json hooks. Confirmed unaddressed as of Claude Code v2.1.172 (v2.1.172's pre-warmed-worker settings-leak fix is a different mechanism). Referencing this thread because the May 2026 comment here documents the same per-agent hooks: frontmatter being ignored.

  12. tehlowkeywiz commented on Jul 11, 2026

    @tehlowkeywiz

    Adding a data point on Claude Code 2.1.206 (2026-07-10): the tools / disallowedTools frontmatter fields are still not enforced for teammate agents, even though (per the May update above on 2.1.150) body, memory, skills, and model now apply. Note that the 2.1.150 test above didn't cover tool restrictions — so this may be a never-fixed remainder of the original report rather than a regression.

    Setup

    Custom agent definition at ~/.claude/agents/code-reviewer.md (agent teams enabled via CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1):

    ---
    name: code-reviewer
    tools: Read, Bash, mcp__linear-server__get_issue, mcp__linear-server__list_comments
    disallowedTools: Write, Edit, mcp__linear-server__save_issue, mcp__linear-server__save_comment
    model: sonnet
    memory: user
    ---

    From a fresh session (started after the definition was last modified — ruling out the stale-registry effect where mid-session edits to agents/*.md don't reach new spawns), I spawned the same agent type two ways and asked each to (a) enumerate its available tools and (b) attempt exactly one Write to a scratch path and report the verbatim tool result.

    Results

    Spawn path Tool surface reported by the agent Write attempt Restrictions enforced?
    Teammate — Agent tool with a name (team member) Read, Bash, mcp__linear-server__get_issue, mcp__linear-server__list_comments, Write, Edit, SendMessage, TaskCreate, TaskGet, TaskList, TaskUpdate — i.e. the allowlist plus what looks like a baseline teammate toolset Succeeded: "File created successfully at: <scratch path>" — file existence and content verified on disk by the parent session ❌ No
    One-shot subagent — same subagent_type, no name Read, Bash, mcp__linear-server__get_issue, mcp__linear-server__list_comments — exactly the allowlist N/A — no Write tool present in its surface to attempt ✅ Yes

    So enforcement diverges by spawn path on the same definition in the same session: one-shot subagents get exactly the allowlist; teammates get the allowlist plus Write, Edit, SendMessage, and the Task* tools regardless of disallowedTools.

    Why it matters

    The agent-teams docs state the teammate "honors that definition's tools allowlist," and the natural use case is read-only roles (e.g. a code reviewer that can inspect but not modify). On the teammate path that read-only posture is currently convention-only — the agent has live Write/Edit capability and nothing but its system prompt discouraging their use.

    Happy to provide the full probe transcripts if useful.

  13. github-actions commented on Sep 10, 2026

    @github-actions

    This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.

  14. locked as resolved and limited conversation to collaborators on Sep 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:agentsbugSomething isn't workinghas reproHas detailed reproduction steps

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions