[Feature]: Configurable instruction files injected into the system prompt, per provider and per project #4490

Description

@Artemonim

Before submitting

  • I searched existing issues and did not find a duplicate.
  • I am describing a concrete problem or use case, not just a vague idea.

Area

apps/desktop

Problem or use case

T3 Code delegates instruction loading to each provider's native discovery of hard-coded filenames: CLAUDE.md via settingSources for Claude, AGENTS.md for Codex. There is no way to say "also load this file, from this path, for this provider instance."

Two problems follow.

1. Provider instances pointed at a non-default backend have nowhere to put backend-specific rules.

A common setup is claudex: the Claude Code CLI driven against OpenAI's Codex backend through a local CLIProxyAPI on 127.0.0.1:8317, billed against a ChatGPT subscription, with ANTHROPIC_BASE_URL and ANTHROPIC_AUTH_TOKEN overridden. It is the same harness — same tools, same skills — with a different model underneath.

That configuration needs its own rules, because behaviour differs from stock Claude Code: ENABLE_TOOL_SEARCH is off (deferred-tool discovery is unreliable on non-Claude models), tool-use concurrency is capped (the backend handles bursts poorly), and the subagent roster differs. Those rules must apply to that provider instance only — they are wrong for a stock Claude thread — and there is currently no slot for them anywhere.

2. The Claude provider never sees AGENTS.md.

Claude Code discovers CLAUDE.md, not AGENTS.md. In a repo that standardised on AGENTS.md — as this one has — a Claude thread starts with the agent unaware of the repo's own conventions, and the user re-supplies them by hand in the first message of every thread. The file is sitting in the working directory; nothing reads it.

Proposed solution

A settings list of instruction files that T3 Code reads and assembles itself, instead of delegating to provider filename conventions.

  • Entries are paths — absolute, ~-relative, or repo-root-relative.
  • Two scopes — global (every project) and per-project (stored with the project, so a repo's own file is picked up automatically on switch).
  • Per-entry provider filterclaude, codex, *, or a specific provider instance. Rules written for one backend must not leak into a thread running on another.
  • Ordered; T3 reads and concatenates. All applicable entries are read in order, joined into one payload, and handed to the provider through its native mechanism (--append-system-prompt-file for Claude, the equivalent config path for Codex; or as prefix to the first prompt in the new chat).
  • Missing files are skipped, not fatal — with a visible note in the work log, so a typo'd path doesn't fail silently.

The concatenation is load-bearing, not an implementation detail: claude keeps only the last--append-system-prompt-file and silently discards earlier ones. Multiple sources can only be delivered as a single merged file.

Ordering and framing. When both user-level and repo-level entries are active, repo content should land after user-level content, wrapped in a short block identifying it as repository content, with the user-level rules re-asserted afterwards. A repo instruction file is third-party data — in a cloned repo it may be adversarial — and should not sit where it appears to override the user's own rules. Only whatever assembles the payload can apply that framing.

Why this matters

Anyone running a provider instance against a non-default backend needs per-instance rules, and today has nowhere to put them. If you working in an AGENTS.md repo through the Claude provider you may manually re-supplying context on every new thread.

Both are currently solved on my side with a shell wrapper that sits between the user and the CLI. That works from a terminal and is structurally impossible in T3 Code, because T3 Code invokes the provider itself — there is no seam for a launcher. Users who have this working in their terminal cannot bring it to the GUI, which is a concrete reason to keep a terminal open alongside T3 Code.

It also removes a class of silent failure. Passing the flag twice looks like it works and quietly drops the first file; a repo-relative path in a static argument string never resolves. Both fail without an error message.

Smallest useful scope

  • For the Claude provider, load the repo-root AGENTS.md in addition to CLAUDE.md.
  • For the Claudex, load the user CLAUDEX and repo-root AGENTS.md in addition to CLAUDE.md.

Alternatives considered

Launch arguments (#1971, #2892). The closest existing mechanism, and for one static absolute path it may already work. It cannot be extended to cover this:

  1. The operation needed is file I/O, not an argument. Sources must be read from disk, concatenated, and framed before the CLI is invoked. Launch arguments are a static string; there is no read step in that path. Note that allowing repeated flags in the launch-args parser would not fix this — claude itself also keeps only the last one, so the merge is mandatory regardless of how arguments are stored.
  2. Static strings are not interpolated against the working directory, so ./AGENTS.md cannot be expressed. Only an absolute path works, re-edited in settings on every project switch — which defeats the purpose for the most common case.
  3. No project scope. Launch arguments belong to a provider instance, not a project.
  4. No validation, ordering, or framing. Nothing checks the path exists or controls what lands where.

A wrapper script. What I use today outside T3 Code: it reads the claudex rules file and the repo's AGENTS.md, merges them into one temp file, frames the repo section as content that cannot override the rules above it, re-asserts those rules after it, passes the result via --append-system-prompt-file, refuses to launch if the rules file is missing, and rejects any user-supplied --append-system-prompt* flag that would silently replace the merged payload. Every step is file I/O and string assembly performed before the CLI starts — which is exactly why it cannot be expressed as configuration, and why it doesn't survive the move into T3 Code.

Symlinking AGENTS.md to CLAUDE.md. Works per-repo, pollutes the repo or the ignore file, and does nothing for problem 1.

Risks or tradeoffs

  • Prompt-injection surface. Auto-loading a repo file means cloning a repo can inject text into the system prompt. This is already true of native AGENTS.md/CLAUDE.md discovery, but a configurable list widens it. Mitigated by the framing block described above, and by keeping repo-scoped entries opt-in per project.
  • Provider divergence. Each provider has a different injection mechanism, and Codex's is config-based rather than a flag. The abstraction has to be "assemble a payload, hand it to the adapter" rather than "pass this flag."
  • Reload semantics. If a file changes mid-thread, is it re-read? Simplest answer is no — read at session start only — but it should be a stated choice rather than an accident.
  • Interaction with [Feature]: Session-scoped notes panel — agent-shared and user-private regions #2397 (session notes) — both inject text into the system context and should share one assembly path rather than growing two.

Examples or references

claudex setup guide (the configuration described above): https://claude.ai/code/artifact/e0a0e13e-6f60-4615-8e4b-3a8b8e3d1c41

Prior art for the general shape — user-specified files merged into the system prompt, with scope layering:

Related in this repo: #1233 (global agent prompt, single fixed file, no provider filter), #1283 / #1334 (native Claude setting sources; standard filenames only), #2397 (session-scoped notes), #1971 / #2892 (provider launch arguments, the current workaround), #737 and #1740 (adjacent prompt/skill/subagent customisation).

Contribution

  • I would be open to helping implement this.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementRequested improvement or new capability.needs-triageIssue needs maintainer review and initial categorization.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      , 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
       blocks
      (function() {
      function addCopyButtons() {
      document.querySelectorAll('pre code').forEach(function(codeBlock) {
      if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
      codeBlock.parentElement.setAttribute('data-copy-added', 'true');
      var btn = document.createElement('button');
      btn.textContent = 'Copy';
      btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
      btn.onmouseover = function() { this.style.opacity = '1'; };
      btn.onmouseout = function() { this.style.opacity = '0.7'; };
      btn.onclick = function() {
      navigator.clipboard.writeText(codeBlock.textContent).then(function() {
      btn.textContent = 'Copied!';
      setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
      });
      };
      codeBlock.parentElement.style.position = 'relative';
      codeBlock.parentElement.appendChild(btn);
      });
      }
      addCopyButtons();
      // Re-run on dynamic content
      var observer = new MutationObserver(addCopyButtons);
      observer.observe(document.body, { childList: true, subtree: true });
      })();
      }
      } catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
      })();
      (function(){
      try {
      var __m = "github.com";
      var __re = new RegExp('^' + "github\\.com" + '
      
      Skip to content

      [Feature]: Configurable instruction files injected into the system prompt, per provider and per project #4490

      Description

      @Artemonim

      Before submitting

      • I searched existing issues and did not find a duplicate.
      • I am describing a concrete problem or use case, not just a vague idea.

      Area

      apps/desktop

      Problem or use case

      T3 Code delegates instruction loading to each provider's native discovery of hard-coded filenames: CLAUDE.md via settingSources for Claude, AGENTS.md for Codex. There is no way to say "also load this file, from this path, for this provider instance."

      Two problems follow.

      1. Provider instances pointed at a non-default backend have nowhere to put backend-specific rules.

      A common setup is claudex: the Claude Code CLI driven against OpenAI's Codex backend through a local CLIProxyAPI on 127.0.0.1:8317, billed against a ChatGPT subscription, with ANTHROPIC_BASE_URL and ANTHROPIC_AUTH_TOKEN overridden. It is the same harness — same tools, same skills — with a different model underneath.

      That configuration needs its own rules, because behaviour differs from stock Claude Code: ENABLE_TOOL_SEARCH is off (deferred-tool discovery is unreliable on non-Claude models), tool-use concurrency is capped (the backend handles bursts poorly), and the subagent roster differs. Those rules must apply to that provider instance only — they are wrong for a stock Claude thread — and there is currently no slot for them anywhere.

      2. The Claude provider never sees AGENTS.md.

      Claude Code discovers CLAUDE.md, not AGENTS.md. In a repo that standardised on AGENTS.md — as this one has — a Claude thread starts with the agent unaware of the repo's own conventions, and the user re-supplies them by hand in the first message of every thread. The file is sitting in the working directory; nothing reads it.

      Proposed solution

      A settings list of instruction files that T3 Code reads and assembles itself, instead of delegating to provider filename conventions.

      • Entries are paths — absolute, ~-relative, or repo-root-relative.
      • Two scopes — global (every project) and per-project (stored with the project, so a repo's own file is picked up automatically on switch).
      • Per-entry provider filterclaude, codex, *, or a specific provider instance. Rules written for one backend must not leak into a thread running on another.
      • Ordered; T3 reads and concatenates. All applicable entries are read in order, joined into one payload, and handed to the provider through its native mechanism (--append-system-prompt-file for Claude, the equivalent config path for Codex; or as prefix to the first prompt in the new chat).
      • Missing files are skipped, not fatal — with a visible note in the work log, so a typo'd path doesn't fail silently.

      The concatenation is load-bearing, not an implementation detail: claude keeps only the last--append-system-prompt-file and silently discards earlier ones. Multiple sources can only be delivered as a single merged file.

      Ordering and framing. When both user-level and repo-level entries are active, repo content should land after user-level content, wrapped in a short block identifying it as repository content, with the user-level rules re-asserted afterwards. A repo instruction file is third-party data — in a cloned repo it may be adversarial — and should not sit where it appears to override the user's own rules. Only whatever assembles the payload can apply that framing.

      Why this matters

      Anyone running a provider instance against a non-default backend needs per-instance rules, and today has nowhere to put them. If you working in an AGENTS.md repo through the Claude provider you may manually re-supplying context on every new thread.

      Both are currently solved on my side with a shell wrapper that sits between the user and the CLI. That works from a terminal and is structurally impossible in T3 Code, because T3 Code invokes the provider itself — there is no seam for a launcher. Users who have this working in their terminal cannot bring it to the GUI, which is a concrete reason to keep a terminal open alongside T3 Code.

      It also removes a class of silent failure. Passing the flag twice looks like it works and quietly drops the first file; a repo-relative path in a static argument string never resolves. Both fail without an error message.

      Smallest useful scope

      • For the Claude provider, load the repo-root AGENTS.md in addition to CLAUDE.md.
      • For the Claudex, load the user CLAUDEX and repo-root AGENTS.md in addition to CLAUDE.md.

      Alternatives considered

      Launch arguments (#1971, #2892). The closest existing mechanism, and for one static absolute path it may already work. It cannot be extended to cover this:

      1. The operation needed is file I/O, not an argument. Sources must be read from disk, concatenated, and framed before the CLI is invoked. Launch arguments are a static string; there is no read step in that path. Note that allowing repeated flags in the launch-args parser would not fix this — claude itself also keeps only the last one, so the merge is mandatory regardless of how arguments are stored.
      2. Static strings are not interpolated against the working directory, so ./AGENTS.md cannot be expressed. Only an absolute path works, re-edited in settings on every project switch — which defeats the purpose for the most common case.
      3. No project scope. Launch arguments belong to a provider instance, not a project.
      4. No validation, ordering, or framing. Nothing checks the path exists or controls what lands where.

      A wrapper script. What I use today outside T3 Code: it reads the claudex rules file and the repo's AGENTS.md, merges them into one temp file, frames the repo section as content that cannot override the rules above it, re-asserts those rules after it, passes the result via --append-system-prompt-file, refuses to launch if the rules file is missing, and rejects any user-supplied --append-system-prompt* flag that would silently replace the merged payload. Every step is file I/O and string assembly performed before the CLI starts — which is exactly why it cannot be expressed as configuration, and why it doesn't survive the move into T3 Code.

      Symlinking AGENTS.md to CLAUDE.md. Works per-repo, pollutes the repo or the ignore file, and does nothing for problem 1.

      Risks or tradeoffs

      • Prompt-injection surface. Auto-loading a repo file means cloning a repo can inject text into the system prompt. This is already true of native AGENTS.md/CLAUDE.md discovery, but a configurable list widens it. Mitigated by the framing block described above, and by keeping repo-scoped entries opt-in per project.
      • Provider divergence. Each provider has a different injection mechanism, and Codex's is config-based rather than a flag. The abstraction has to be "assemble a payload, hand it to the adapter" rather than "pass this flag."
      • Reload semantics. If a file changes mid-thread, is it re-read? Simplest answer is no — read at session start only — but it should be a stated choice rather than an accident.
      • Interaction with [Feature]: Session-scoped notes panel — agent-shared and user-private regions #2397 (session notes) — both inject text into the system context and should share one assembly path rather than growing two.

      Examples or references

      claudex setup guide (the configuration described above): https://claude.ai/code/artifact/e0a0e13e-6f60-4615-8e4b-3a8b8e3d1c41

      Prior art for the general shape — user-specified files merged into the system prompt, with scope layering:

      Related in this repo: #1233 (global agent prompt, single fixed file, no provider filter), #1283 / #1334 (native Claude setting sources; standard filenames only), #2397 (session-scoped notes), #1971 / #2892 (provider launch arguments, the current workaround), #737 and #1740 (adjacent prompt/skill/subagent customisation).

      Contribution

      • I would be open to helping implement this.

      Metadata

      Metadata

      Assignees

      No one assigned

        Labels

        enhancementRequested improvement or new capability.needs-triageIssue needs maintainer review and initial categorization.

        Type

        No type

        Projects

        No projects

          Milestone

          No milestone

          Relationships

          None yet

          Development

          No branches or pull requests

          Issue actions

          , 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
          Skip to content

          [Feature]: Configurable instruction files injected into the system prompt, per provider and per project #4490

          Description

          @Artemonim

          Before submitting

          • I searched existing issues and did not find a duplicate.
          • I am describing a concrete problem or use case, not just a vague idea.

          Area

          apps/desktop

          Problem or use case

          T3 Code delegates instruction loading to each provider's native discovery of hard-coded filenames: CLAUDE.md via settingSources for Claude, AGENTS.md for Codex. There is no way to say "also load this file, from this path, for this provider instance."

          Two problems follow.

          1. Provider instances pointed at a non-default backend have nowhere to put backend-specific rules.

          A common setup is claudex: the Claude Code CLI driven against OpenAI's Codex backend through a local CLIProxyAPI on 127.0.0.1:8317, billed against a ChatGPT subscription, with ANTHROPIC_BASE_URL and ANTHROPIC_AUTH_TOKEN overridden. It is the same harness — same tools, same skills — with a different model underneath.

          That configuration needs its own rules, because behaviour differs from stock Claude Code: ENABLE_TOOL_SEARCH is off (deferred-tool discovery is unreliable on non-Claude models), tool-use concurrency is capped (the backend handles bursts poorly), and the subagent roster differs. Those rules must apply to that provider instance only — they are wrong for a stock Claude thread — and there is currently no slot for them anywhere.

          2. The Claude provider never sees AGENTS.md.

          Claude Code discovers CLAUDE.md, not AGENTS.md. In a repo that standardised on AGENTS.md — as this one has — a Claude thread starts with the agent unaware of the repo's own conventions, and the user re-supplies them by hand in the first message of every thread. The file is sitting in the working directory; nothing reads it.

          Proposed solution

          A settings list of instruction files that T3 Code reads and assembles itself, instead of delegating to provider filename conventions.

          • Entries are paths — absolute, ~-relative, or repo-root-relative.
          • Two scopes — global (every project) and per-project (stored with the project, so a repo's own file is picked up automatically on switch).
          • Per-entry provider filterclaude, codex, *, or a specific provider instance. Rules written for one backend must not leak into a thread running on another.
          • Ordered; T3 reads and concatenates. All applicable entries are read in order, joined into one payload, and handed to the provider through its native mechanism (--append-system-prompt-file for Claude, the equivalent config path for Codex; or as prefix to the first prompt in the new chat).
          • Missing files are skipped, not fatal — with a visible note in the work log, so a typo'd path doesn't fail silently.

          The concatenation is load-bearing, not an implementation detail: claude keeps only the last--append-system-prompt-file and silently discards earlier ones. Multiple sources can only be delivered as a single merged file.

          Ordering and framing. When both user-level and repo-level entries are active, repo content should land after user-level content, wrapped in a short block identifying it as repository content, with the user-level rules re-asserted afterwards. A repo instruction file is third-party data — in a cloned repo it may be adversarial — and should not sit where it appears to override the user's own rules. Only whatever assembles the payload can apply that framing.

          Why this matters

          Anyone running a provider instance against a non-default backend needs per-instance rules, and today has nowhere to put them. If you working in an AGENTS.md repo through the Claude provider you may manually re-supplying context on every new thread.

          Both are currently solved on my side with a shell wrapper that sits between the user and the CLI. That works from a terminal and is structurally impossible in T3 Code, because T3 Code invokes the provider itself — there is no seam for a launcher. Users who have this working in their terminal cannot bring it to the GUI, which is a concrete reason to keep a terminal open alongside T3 Code.

          It also removes a class of silent failure. Passing the flag twice looks like it works and quietly drops the first file; a repo-relative path in a static argument string never resolves. Both fail without an error message.

          Smallest useful scope

          • For the Claude provider, load the repo-root AGENTS.md in addition to CLAUDE.md.
          • For the Claudex, load the user CLAUDEX and repo-root AGENTS.md in addition to CLAUDE.md.

          Alternatives considered

          Launch arguments (#1971, #2892). The closest existing mechanism, and for one static absolute path it may already work. It cannot be extended to cover this:

          1. The operation needed is file I/O, not an argument. Sources must be read from disk, concatenated, and framed before the CLI is invoked. Launch arguments are a static string; there is no read step in that path. Note that allowing repeated flags in the launch-args parser would not fix this — claude itself also keeps only the last one, so the merge is mandatory regardless of how arguments are stored.
          2. Static strings are not interpolated against the working directory, so ./AGENTS.md cannot be expressed. Only an absolute path works, re-edited in settings on every project switch — which defeats the purpose for the most common case.
          3. No project scope. Launch arguments belong to a provider instance, not a project.
          4. No validation, ordering, or framing. Nothing checks the path exists or controls what lands where.

          A wrapper script. What I use today outside T3 Code: it reads the claudex rules file and the repo's AGENTS.md, merges them into one temp file, frames the repo section as content that cannot override the rules above it, re-asserts those rules after it, passes the result via --append-system-prompt-file, refuses to launch if the rules file is missing, and rejects any user-supplied --append-system-prompt* flag that would silently replace the merged payload. Every step is file I/O and string assembly performed before the CLI starts — which is exactly why it cannot be expressed as configuration, and why it doesn't survive the move into T3 Code.

          Symlinking AGENTS.md to CLAUDE.md. Works per-repo, pollutes the repo or the ignore file, and does nothing for problem 1.

          Risks or tradeoffs

          • Prompt-injection surface. Auto-loading a repo file means cloning a repo can inject text into the system prompt. This is already true of native AGENTS.md/CLAUDE.md discovery, but a configurable list widens it. Mitigated by the framing block described above, and by keeping repo-scoped entries opt-in per project.
          • Provider divergence. Each provider has a different injection mechanism, and Codex's is config-based rather than a flag. The abstraction has to be "assemble a payload, hand it to the adapter" rather than "pass this flag."
          • Reload semantics. If a file changes mid-thread, is it re-read? Simplest answer is no — read at session start only — but it should be a stated choice rather than an accident.
          • Interaction with [Feature]: Session-scoped notes panel — agent-shared and user-private regions #2397 (session notes) — both inject text into the system context and should share one assembly path rather than growing two.

          Examples or references

          claudex setup guide (the configuration described above): https://claude.ai/code/artifact/e0a0e13e-6f60-4615-8e4b-3a8b8e3d1c41

          Prior art for the general shape — user-specified files merged into the system prompt, with scope layering:

          Related in this repo: #1233 (global agent prompt, single fixed file, no provider filter), #1283 / #1334 (native Claude setting sources; standard filenames only), #2397 (session-scoped notes), #1971 / #2892 (provider launch arguments, the current workaround), #737 and #1740 (adjacent prompt/skill/subagent customisation).

          Contribution

          • I would be open to helping implement this.

          Metadata

          Metadata

          Assignees

          No one assigned

            Labels

            enhancementRequested improvement or new capability.needs-triageIssue needs maintainer review and initial categorization.

            Type

            No type

            Projects

            No projects

              Milestone

              No milestone

              Relationships

              None yet

              Development

              No branches or pull requests

              Issue actions

              , 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
              Skip to content

              [Feature]: Configurable instruction files injected into the system prompt, per provider and per project #4490

              Description

              @Artemonim

              Before submitting

              • I searched existing issues and did not find a duplicate.
              • I am describing a concrete problem or use case, not just a vague idea.

              Area

              apps/desktop

              Problem or use case

              T3 Code delegates instruction loading to each provider's native discovery of hard-coded filenames: CLAUDE.md via settingSources for Claude, AGENTS.md for Codex. There is no way to say "also load this file, from this path, for this provider instance."

              Two problems follow.

              1. Provider instances pointed at a non-default backend have nowhere to put backend-specific rules.

              A common setup is claudex: the Claude Code CLI driven against OpenAI's Codex backend through a local CLIProxyAPI on 127.0.0.1:8317, billed against a ChatGPT subscription, with ANTHROPIC_BASE_URL and ANTHROPIC_AUTH_TOKEN overridden. It is the same harness — same tools, same skills — with a different model underneath.

              That configuration needs its own rules, because behaviour differs from stock Claude Code: ENABLE_TOOL_SEARCH is off (deferred-tool discovery is unreliable on non-Claude models), tool-use concurrency is capped (the backend handles bursts poorly), and the subagent roster differs. Those rules must apply to that provider instance only — they are wrong for a stock Claude thread — and there is currently no slot for them anywhere.

              2. The Claude provider never sees AGENTS.md.

              Claude Code discovers CLAUDE.md, not AGENTS.md. In a repo that standardised on AGENTS.md — as this one has — a Claude thread starts with the agent unaware of the repo's own conventions, and the user re-supplies them by hand in the first message of every thread. The file is sitting in the working directory; nothing reads it.

              Proposed solution

              A settings list of instruction files that T3 Code reads and assembles itself, instead of delegating to provider filename conventions.

              • Entries are paths — absolute, ~-relative, or repo-root-relative.
              • Two scopes — global (every project) and per-project (stored with the project, so a repo's own file is picked up automatically on switch).
              • Per-entry provider filterclaude, codex, *, or a specific provider instance. Rules written for one backend must not leak into a thread running on another.
              • Ordered; T3 reads and concatenates. All applicable entries are read in order, joined into one payload, and handed to the provider through its native mechanism (--append-system-prompt-file for Claude, the equivalent config path for Codex; or as prefix to the first prompt in the new chat).
              • Missing files are skipped, not fatal — with a visible note in the work log, so a typo'd path doesn't fail silently.

              The concatenation is load-bearing, not an implementation detail: claude keeps only the last--append-system-prompt-file and silently discards earlier ones. Multiple sources can only be delivered as a single merged file.

              Ordering and framing. When both user-level and repo-level entries are active, repo content should land after user-level content, wrapped in a short block identifying it as repository content, with the user-level rules re-asserted afterwards. A repo instruction file is third-party data — in a cloned repo it may be adversarial — and should not sit where it appears to override the user's own rules. Only whatever assembles the payload can apply that framing.

              Why this matters

              Anyone running a provider instance against a non-default backend needs per-instance rules, and today has nowhere to put them. If you working in an AGENTS.md repo through the Claude provider you may manually re-supplying context on every new thread.

              Both are currently solved on my side with a shell wrapper that sits between the user and the CLI. That works from a terminal and is structurally impossible in T3 Code, because T3 Code invokes the provider itself — there is no seam for a launcher. Users who have this working in their terminal cannot bring it to the GUI, which is a concrete reason to keep a terminal open alongside T3 Code.

              It also removes a class of silent failure. Passing the flag twice looks like it works and quietly drops the first file; a repo-relative path in a static argument string never resolves. Both fail without an error message.

              Smallest useful scope

              • For the Claude provider, load the repo-root AGENTS.md in addition to CLAUDE.md.
              • For the Claudex, load the user CLAUDEX and repo-root AGENTS.md in addition to CLAUDE.md.

              Alternatives considered

              Launch arguments (#1971, #2892). The closest existing mechanism, and for one static absolute path it may already work. It cannot be extended to cover this:

              1. The operation needed is file I/O, not an argument. Sources must be read from disk, concatenated, and framed before the CLI is invoked. Launch arguments are a static string; there is no read step in that path. Note that allowing repeated flags in the launch-args parser would not fix this — claude itself also keeps only the last one, so the merge is mandatory regardless of how arguments are stored.
              2. Static strings are not interpolated against the working directory, so ./AGENTS.md cannot be expressed. Only an absolute path works, re-edited in settings on every project switch — which defeats the purpose for the most common case.
              3. No project scope. Launch arguments belong to a provider instance, not a project.
              4. No validation, ordering, or framing. Nothing checks the path exists or controls what lands where.

              A wrapper script. What I use today outside T3 Code: it reads the claudex rules file and the repo's AGENTS.md, merges them into one temp file, frames the repo section as content that cannot override the rules above it, re-asserts those rules after it, passes the result via --append-system-prompt-file, refuses to launch if the rules file is missing, and rejects any user-supplied --append-system-prompt* flag that would silently replace the merged payload. Every step is file I/O and string assembly performed before the CLI starts — which is exactly why it cannot be expressed as configuration, and why it doesn't survive the move into T3 Code.

              Symlinking AGENTS.md to CLAUDE.md. Works per-repo, pollutes the repo or the ignore file, and does nothing for problem 1.

              Risks or tradeoffs

              • Prompt-injection surface. Auto-loading a repo file means cloning a repo can inject text into the system prompt. This is already true of native AGENTS.md/CLAUDE.md discovery, but a configurable list widens it. Mitigated by the framing block described above, and by keeping repo-scoped entries opt-in per project.
              • Provider divergence. Each provider has a different injection mechanism, and Codex's is config-based rather than a flag. The abstraction has to be "assemble a payload, hand it to the adapter" rather than "pass this flag."
              • Reload semantics. If a file changes mid-thread, is it re-read? Simplest answer is no — read at session start only — but it should be a stated choice rather than an accident.
              • Interaction with [Feature]: Session-scoped notes panel — agent-shared and user-private regions #2397 (session notes) — both inject text into the system context and should share one assembly path rather than growing two.

              Examples or references

              claudex setup guide (the configuration described above): https://claude.ai/code/artifact/e0a0e13e-6f60-4615-8e4b-3a8b8e3d1c41

              Prior art for the general shape — user-specified files merged into the system prompt, with scope layering:

              Related in this repo: #1233 (global agent prompt, single fixed file, no provider filter), #1283 / #1334 (native Claude setting sources; standard filenames only), #2397 (session-scoped notes), #1971 / #2892 (provider launch arguments, the current workaround), #737 and #1740 (adjacent prompt/skill/subagent customisation).

              Contribution

              • I would be open to helping implement this.

              Metadata

              Metadata

              Assignees

              No one assigned

                Labels

                enhancementRequested improvement or new capability.needs-triageIssue needs maintainer review and initial categorization.

                Type

                No type

                Projects

                No projects

                  Milestone

                  No milestone

                  Relationships

                  None yet

                  Development

                  No branches or pull requests

                  Issue actions

                  , 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
                  Skip to content

                  [Feature]: Configurable instruction files injected into the system prompt, per provider and per project #4490

                  Description

                  @Artemonim

                  Before submitting

                  • I searched existing issues and did not find a duplicate.
                  • I am describing a concrete problem or use case, not just a vague idea.

                  Area

                  apps/desktop

                  Problem or use case

                  T3 Code delegates instruction loading to each provider's native discovery of hard-coded filenames: CLAUDE.md via settingSources for Claude, AGENTS.md for Codex. There is no way to say "also load this file, from this path, for this provider instance."

                  Two problems follow.

                  1. Provider instances pointed at a non-default backend have nowhere to put backend-specific rules.

                  A common setup is claudex: the Claude Code CLI driven against OpenAI's Codex backend through a local CLIProxyAPI on 127.0.0.1:8317, billed against a ChatGPT subscription, with ANTHROPIC_BASE_URL and ANTHROPIC_AUTH_TOKEN overridden. It is the same harness — same tools, same skills — with a different model underneath.

                  That configuration needs its own rules, because behaviour differs from stock Claude Code: ENABLE_TOOL_SEARCH is off (deferred-tool discovery is unreliable on non-Claude models), tool-use concurrency is capped (the backend handles bursts poorly), and the subagent roster differs. Those rules must apply to that provider instance only — they are wrong for a stock Claude thread — and there is currently no slot for them anywhere.

                  2. The Claude provider never sees AGENTS.md.

                  Claude Code discovers CLAUDE.md, not AGENTS.md. In a repo that standardised on AGENTS.md — as this one has — a Claude thread starts with the agent unaware of the repo's own conventions, and the user re-supplies them by hand in the first message of every thread. The file is sitting in the working directory; nothing reads it.

                  Proposed solution

                  A settings list of instruction files that T3 Code reads and assembles itself, instead of delegating to provider filename conventions.

                  • Entries are paths — absolute, ~-relative, or repo-root-relative.
                  • Two scopes — global (every project) and per-project (stored with the project, so a repo's own file is picked up automatically on switch).
                  • Per-entry provider filterclaude, codex, *, or a specific provider instance. Rules written for one backend must not leak into a thread running on another.
                  • Ordered; T3 reads and concatenates. All applicable entries are read in order, joined into one payload, and handed to the provider through its native mechanism (--append-system-prompt-file for Claude, the equivalent config path for Codex; or as prefix to the first prompt in the new chat).
                  • Missing files are skipped, not fatal — with a visible note in the work log, so a typo'd path doesn't fail silently.

                  The concatenation is load-bearing, not an implementation detail: claude keeps only the last--append-system-prompt-file and silently discards earlier ones. Multiple sources can only be delivered as a single merged file.

                  Ordering and framing. When both user-level and repo-level entries are active, repo content should land after user-level content, wrapped in a short block identifying it as repository content, with the user-level rules re-asserted afterwards. A repo instruction file is third-party data — in a cloned repo it may be adversarial — and should not sit where it appears to override the user's own rules. Only whatever assembles the payload can apply that framing.

                  Why this matters

                  Anyone running a provider instance against a non-default backend needs per-instance rules, and today has nowhere to put them. If you working in an AGENTS.md repo through the Claude provider you may manually re-supplying context on every new thread.

                  Both are currently solved on my side with a shell wrapper that sits between the user and the CLI. That works from a terminal and is structurally impossible in T3 Code, because T3 Code invokes the provider itself — there is no seam for a launcher. Users who have this working in their terminal cannot bring it to the GUI, which is a concrete reason to keep a terminal open alongside T3 Code.

                  It also removes a class of silent failure. Passing the flag twice looks like it works and quietly drops the first file; a repo-relative path in a static argument string never resolves. Both fail without an error message.

                  Smallest useful scope

                  • For the Claude provider, load the repo-root AGENTS.md in addition to CLAUDE.md.
                  • For the Claudex, load the user CLAUDEX and repo-root AGENTS.md in addition to CLAUDE.md.

                  Alternatives considered

                  Launch arguments (#1971, #2892). The closest existing mechanism, and for one static absolute path it may already work. It cannot be extended to cover this:

                  1. The operation needed is file I/O, not an argument. Sources must be read from disk, concatenated, and framed before the CLI is invoked. Launch arguments are a static string; there is no read step in that path. Note that allowing repeated flags in the launch-args parser would not fix this — claude itself also keeps only the last one, so the merge is mandatory regardless of how arguments are stored.
                  2. Static strings are not interpolated against the working directory, so ./AGENTS.md cannot be expressed. Only an absolute path works, re-edited in settings on every project switch — which defeats the purpose for the most common case.
                  3. No project scope. Launch arguments belong to a provider instance, not a project.
                  4. No validation, ordering, or framing. Nothing checks the path exists or controls what lands where.

                  A wrapper script. What I use today outside T3 Code: it reads the claudex rules file and the repo's AGENTS.md, merges them into one temp file, frames the repo section as content that cannot override the rules above it, re-asserts those rules after it, passes the result via --append-system-prompt-file, refuses to launch if the rules file is missing, and rejects any user-supplied --append-system-prompt* flag that would silently replace the merged payload. Every step is file I/O and string assembly performed before the CLI starts — which is exactly why it cannot be expressed as configuration, and why it doesn't survive the move into T3 Code.

                  Symlinking AGENTS.md to CLAUDE.md. Works per-repo, pollutes the repo or the ignore file, and does nothing for problem 1.

                  Risks or tradeoffs

                  • Prompt-injection surface. Auto-loading a repo file means cloning a repo can inject text into the system prompt. This is already true of native AGENTS.md/CLAUDE.md discovery, but a configurable list widens it. Mitigated by the framing block described above, and by keeping repo-scoped entries opt-in per project.
                  • Provider divergence. Each provider has a different injection mechanism, and Codex's is config-based rather than a flag. The abstraction has to be "assemble a payload, hand it to the adapter" rather than "pass this flag."
                  • Reload semantics. If a file changes mid-thread, is it re-read? Simplest answer is no — read at session start only — but it should be a stated choice rather than an accident.
                  • Interaction with [Feature]: Session-scoped notes panel — agent-shared and user-private regions #2397 (session notes) — both inject text into the system context and should share one assembly path rather than growing two.

                  Examples or references

                  claudex setup guide (the configuration described above): https://claude.ai/code/artifact/e0a0e13e-6f60-4615-8e4b-3a8b8e3d1c41

                  Prior art for the general shape — user-specified files merged into the system prompt, with scope layering:

                  Related in this repo: #1233 (global agent prompt, single fixed file, no provider filter), #1283 / #1334 (native Claude setting sources; standard filenames only), #2397 (session-scoped notes), #1971 / #2892 (provider launch arguments, the current workaround), #737 and #1740 (adjacent prompt/skill/subagent customisation).

                  Contribution

                  • I would be open to helping implement this.

                  Metadata

                  Metadata

                  Assignees

                  No one assigned

                    Labels

                    enhancementRequested improvement or new capability.needs-triageIssue needs maintainer review and initial categorization.

                    Type

                    No type

                    Projects

                    No projects

                      Milestone

                      No milestone

                      Relationships

                      None yet

                      Development

                      No branches or pull requests

                      Issue actions

                      , 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
                      Skip to content

                      [Feature]: Configurable instruction files injected into the system prompt, per provider and per project #4490

                      Description

                      @Artemonim

                      Before submitting

                      • I searched existing issues and did not find a duplicate.
                      • I am describing a concrete problem or use case, not just a vague idea.

                      Area

                      apps/desktop

                      Problem or use case

                      T3 Code delegates instruction loading to each provider's native discovery of hard-coded filenames: CLAUDE.md via settingSources for Claude, AGENTS.md for Codex. There is no way to say "also load this file, from this path, for this provider instance."

                      Two problems follow.

                      1. Provider instances pointed at a non-default backend have nowhere to put backend-specific rules.

                      A common setup is claudex: the Claude Code CLI driven against OpenAI's Codex backend through a local CLIProxyAPI on 127.0.0.1:8317, billed against a ChatGPT subscription, with ANTHROPIC_BASE_URL and ANTHROPIC_AUTH_TOKEN overridden. It is the same harness — same tools, same skills — with a different model underneath.

                      That configuration needs its own rules, because behaviour differs from stock Claude Code: ENABLE_TOOL_SEARCH is off (deferred-tool discovery is unreliable on non-Claude models), tool-use concurrency is capped (the backend handles bursts poorly), and the subagent roster differs. Those rules must apply to that provider instance only — they are wrong for a stock Claude thread — and there is currently no slot for them anywhere.

                      2. The Claude provider never sees AGENTS.md.

                      Claude Code discovers CLAUDE.md, not AGENTS.md. In a repo that standardised on AGENTS.md — as this one has — a Claude thread starts with the agent unaware of the repo's own conventions, and the user re-supplies them by hand in the first message of every thread. The file is sitting in the working directory; nothing reads it.

                      Proposed solution

                      A settings list of instruction files that T3 Code reads and assembles itself, instead of delegating to provider filename conventions.

                      • Entries are paths — absolute, ~-relative, or repo-root-relative.
                      • Two scopes — global (every project) and per-project (stored with the project, so a repo's own file is picked up automatically on switch).
                      • Per-entry provider filterclaude, codex, *, or a specific provider instance. Rules written for one backend must not leak into a thread running on another.
                      • Ordered; T3 reads and concatenates. All applicable entries are read in order, joined into one payload, and handed to the provider through its native mechanism (--append-system-prompt-file for Claude, the equivalent config path for Codex; or as prefix to the first prompt in the new chat).
                      • Missing files are skipped, not fatal — with a visible note in the work log, so a typo'd path doesn't fail silently.

                      The concatenation is load-bearing, not an implementation detail: claude keeps only the last--append-system-prompt-file and silently discards earlier ones. Multiple sources can only be delivered as a single merged file.

                      Ordering and framing. When both user-level and repo-level entries are active, repo content should land after user-level content, wrapped in a short block identifying it as repository content, with the user-level rules re-asserted afterwards. A repo instruction file is third-party data — in a cloned repo it may be adversarial — and should not sit where it appears to override the user's own rules. Only whatever assembles the payload can apply that framing.

                      Why this matters

                      Anyone running a provider instance against a non-default backend needs per-instance rules, and today has nowhere to put them. If you working in an AGENTS.md repo through the Claude provider you may manually re-supplying context on every new thread.

                      Both are currently solved on my side with a shell wrapper that sits between the user and the CLI. That works from a terminal and is structurally impossible in T3 Code, because T3 Code invokes the provider itself — there is no seam for a launcher. Users who have this working in their terminal cannot bring it to the GUI, which is a concrete reason to keep a terminal open alongside T3 Code.

                      It also removes a class of silent failure. Passing the flag twice looks like it works and quietly drops the first file; a repo-relative path in a static argument string never resolves. Both fail without an error message.

                      Smallest useful scope

                      • For the Claude provider, load the repo-root AGENTS.md in addition to CLAUDE.md.
                      • For the Claudex, load the user CLAUDEX and repo-root AGENTS.md in addition to CLAUDE.md.

                      Alternatives considered

                      Launch arguments (#1971, #2892). The closest existing mechanism, and for one static absolute path it may already work. It cannot be extended to cover this:

                      1. The operation needed is file I/O, not an argument. Sources must be read from disk, concatenated, and framed before the CLI is invoked. Launch arguments are a static string; there is no read step in that path. Note that allowing repeated flags in the launch-args parser would not fix this — claude itself also keeps only the last one, so the merge is mandatory regardless of how arguments are stored.
                      2. Static strings are not interpolated against the working directory, so ./AGENTS.md cannot be expressed. Only an absolute path works, re-edited in settings on every project switch — which defeats the purpose for the most common case.
                      3. No project scope. Launch arguments belong to a provider instance, not a project.
                      4. No validation, ordering, or framing. Nothing checks the path exists or controls what lands where.

                      A wrapper script. What I use today outside T3 Code: it reads the claudex rules file and the repo's AGENTS.md, merges them into one temp file, frames the repo section as content that cannot override the rules above it, re-asserts those rules after it, passes the result via --append-system-prompt-file, refuses to launch if the rules file is missing, and rejects any user-supplied --append-system-prompt* flag that would silently replace the merged payload. Every step is file I/O and string assembly performed before the CLI starts — which is exactly why it cannot be expressed as configuration, and why it doesn't survive the move into T3 Code.

                      Symlinking AGENTS.md to CLAUDE.md. Works per-repo, pollutes the repo or the ignore file, and does nothing for problem 1.

                      Risks or tradeoffs

                      • Prompt-injection surface. Auto-loading a repo file means cloning a repo can inject text into the system prompt. This is already true of native AGENTS.md/CLAUDE.md discovery, but a configurable list widens it. Mitigated by the framing block described above, and by keeping repo-scoped entries opt-in per project.
                      • Provider divergence. Each provider has a different injection mechanism, and Codex's is config-based rather than a flag. The abstraction has to be "assemble a payload, hand it to the adapter" rather than "pass this flag."
                      • Reload semantics. If a file changes mid-thread, is it re-read? Simplest answer is no — read at session start only — but it should be a stated choice rather than an accident.
                      • Interaction with [Feature]: Session-scoped notes panel — agent-shared and user-private regions #2397 (session notes) — both inject text into the system context and should share one assembly path rather than growing two.

                      Examples or references

                      claudex setup guide (the configuration described above): https://claude.ai/code/artifact/e0a0e13e-6f60-4615-8e4b-3a8b8e3d1c41

                      Prior art for the general shape — user-specified files merged into the system prompt, with scope layering:

                      Related in this repo: #1233 (global agent prompt, single fixed file, no provider filter), #1283 / #1334 (native Claude setting sources; standard filenames only), #2397 (session-scoped notes), #1971 / #2892 (provider launch arguments, the current workaround), #737 and #1740 (adjacent prompt/skill/subagent customisation).

                      Contribution

                      • I would be open to helping implement this.

                      Metadata

                      Metadata

                      Assignees

                      No one assigned

                        Labels

                        enhancementRequested improvement or new capability.needs-triageIssue needs maintainer review and initial categorization.

                        Type

                        No type

                        Projects

                        No projects

                          Milestone

                          No milestone

                          Relationships

                          None yet

                          Development

                          No branches or pull requests

                          Issue actions

                          , 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
                          Skip to content

                          [Feature]: Configurable instruction files injected into the system prompt, per provider and per project #4490

                          Description

                          @Artemonim

                          Before submitting

                          • I searched existing issues and did not find a duplicate.
                          • I am describing a concrete problem or use case, not just a vague idea.

                          Area

                          apps/desktop

                          Problem or use case

                          T3 Code delegates instruction loading to each provider's native discovery of hard-coded filenames: CLAUDE.md via settingSources for Claude, AGENTS.md for Codex. There is no way to say "also load this file, from this path, for this provider instance."

                          Two problems follow.

                          1. Provider instances pointed at a non-default backend have nowhere to put backend-specific rules.

                          A common setup is claudex: the Claude Code CLI driven against OpenAI's Codex backend through a local CLIProxyAPI on 127.0.0.1:8317, billed against a ChatGPT subscription, with ANTHROPIC_BASE_URL and ANTHROPIC_AUTH_TOKEN overridden. It is the same harness — same tools, same skills — with a different model underneath.

                          That configuration needs its own rules, because behaviour differs from stock Claude Code: ENABLE_TOOL_SEARCH is off (deferred-tool discovery is unreliable on non-Claude models), tool-use concurrency is capped (the backend handles bursts poorly), and the subagent roster differs. Those rules must apply to that provider instance only — they are wrong for a stock Claude thread — and there is currently no slot for them anywhere.

                          2. The Claude provider never sees AGENTS.md.

                          Claude Code discovers CLAUDE.md, not AGENTS.md. In a repo that standardised on AGENTS.md — as this one has — a Claude thread starts with the agent unaware of the repo's own conventions, and the user re-supplies them by hand in the first message of every thread. The file is sitting in the working directory; nothing reads it.

                          Proposed solution

                          A settings list of instruction files that T3 Code reads and assembles itself, instead of delegating to provider filename conventions.

                          • Entries are paths — absolute, ~-relative, or repo-root-relative.
                          • Two scopes — global (every project) and per-project (stored with the project, so a repo's own file is picked up automatically on switch).
                          • Per-entry provider filterclaude, codex, *, or a specific provider instance. Rules written for one backend must not leak into a thread running on another.
                          • Ordered; T3 reads and concatenates. All applicable entries are read in order, joined into one payload, and handed to the provider through its native mechanism (--append-system-prompt-file for Claude, the equivalent config path for Codex; or as prefix to the first prompt in the new chat).
                          • Missing files are skipped, not fatal — with a visible note in the work log, so a typo'd path doesn't fail silently.

                          The concatenation is load-bearing, not an implementation detail: claude keeps only the last--append-system-prompt-file and silently discards earlier ones. Multiple sources can only be delivered as a single merged file.

                          Ordering and framing. When both user-level and repo-level entries are active, repo content should land after user-level content, wrapped in a short block identifying it as repository content, with the user-level rules re-asserted afterwards. A repo instruction file is third-party data — in a cloned repo it may be adversarial — and should not sit where it appears to override the user's own rules. Only whatever assembles the payload can apply that framing.

                          Why this matters

                          Anyone running a provider instance against a non-default backend needs per-instance rules, and today has nowhere to put them. If you working in an AGENTS.md repo through the Claude provider you may manually re-supplying context on every new thread.

                          Both are currently solved on my side with a shell wrapper that sits between the user and the CLI. That works from a terminal and is structurally impossible in T3 Code, because T3 Code invokes the provider itself — there is no seam for a launcher. Users who have this working in their terminal cannot bring it to the GUI, which is a concrete reason to keep a terminal open alongside T3 Code.

                          It also removes a class of silent failure. Passing the flag twice looks like it works and quietly drops the first file; a repo-relative path in a static argument string never resolves. Both fail without an error message.

                          Smallest useful scope

                          • For the Claude provider, load the repo-root AGENTS.md in addition to CLAUDE.md.
                          • For the Claudex, load the user CLAUDEX and repo-root AGENTS.md in addition to CLAUDE.md.

                          Alternatives considered

                          Launch arguments (#1971, #2892). The closest existing mechanism, and for one static absolute path it may already work. It cannot be extended to cover this:

                          1. The operation needed is file I/O, not an argument. Sources must be read from disk, concatenated, and framed before the CLI is invoked. Launch arguments are a static string; there is no read step in that path. Note that allowing repeated flags in the launch-args parser would not fix this — claude itself also keeps only the last one, so the merge is mandatory regardless of how arguments are stored.
                          2. Static strings are not interpolated against the working directory, so ./AGENTS.md cannot be expressed. Only an absolute path works, re-edited in settings on every project switch — which defeats the purpose for the most common case.
                          3. No project scope. Launch arguments belong to a provider instance, not a project.
                          4. No validation, ordering, or framing. Nothing checks the path exists or controls what lands where.

                          A wrapper script. What I use today outside T3 Code: it reads the claudex rules file and the repo's AGENTS.md, merges them into one temp file, frames the repo section as content that cannot override the rules above it, re-asserts those rules after it, passes the result via --append-system-prompt-file, refuses to launch if the rules file is missing, and rejects any user-supplied --append-system-prompt* flag that would silently replace the merged payload. Every step is file I/O and string assembly performed before the CLI starts — which is exactly why it cannot be expressed as configuration, and why it doesn't survive the move into T3 Code.

                          Symlinking AGENTS.md to CLAUDE.md. Works per-repo, pollutes the repo or the ignore file, and does nothing for problem 1.

                          Risks or tradeoffs

                          • Prompt-injection surface. Auto-loading a repo file means cloning a repo can inject text into the system prompt. This is already true of native AGENTS.md/CLAUDE.md discovery, but a configurable list widens it. Mitigated by the framing block described above, and by keeping repo-scoped entries opt-in per project.
                          • Provider divergence. Each provider has a different injection mechanism, and Codex's is config-based rather than a flag. The abstraction has to be "assemble a payload, hand it to the adapter" rather than "pass this flag."
                          • Reload semantics. If a file changes mid-thread, is it re-read? Simplest answer is no — read at session start only — but it should be a stated choice rather than an accident.
                          • Interaction with [Feature]: Session-scoped notes panel — agent-shared and user-private regions #2397 (session notes) — both inject text into the system context and should share one assembly path rather than growing two.

                          Examples or references

                          claudex setup guide (the configuration described above): https://claude.ai/code/artifact/e0a0e13e-6f60-4615-8e4b-3a8b8e3d1c41

                          Prior art for the general shape — user-specified files merged into the system prompt, with scope layering:

                          Related in this repo: #1233 (global agent prompt, single fixed file, no provider filter), #1283 / #1334 (native Claude setting sources; standard filenames only), #2397 (session-scoped notes), #1971 / #2892 (provider launch arguments, the current workaround), #737 and #1740 (adjacent prompt/skill/subagent customisation).

                          Contribution

                          • I would be open to helping implement this.

                          Metadata

                          Metadata

                          Assignees

                          No one assigned

                            Labels

                            enhancementRequested improvement or new capability.needs-triageIssue needs maintainer review and initial categorization.

                            Type

                            No type

                            Projects

                            No projects

                              Milestone

                              No milestone

                              Relationships

                              None yet

                              Development

                              No branches or pull requests

                              Issue actions

                              , 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
                              Skip to content

                              [Feature]: Configurable instruction files injected into the system prompt, per provider and per project #4490

                              Description

                              @Artemonim

                              Before submitting

                              • I searched existing issues and did not find a duplicate.
                              • I am describing a concrete problem or use case, not just a vague idea.

                              Area

                              apps/desktop

                              Problem or use case

                              T3 Code delegates instruction loading to each provider's native discovery of hard-coded filenames: CLAUDE.md via settingSources for Claude, AGENTS.md for Codex. There is no way to say "also load this file, from this path, for this provider instance."

                              Two problems follow.

                              1. Provider instances pointed at a non-default backend have nowhere to put backend-specific rules.

                              A common setup is claudex: the Claude Code CLI driven against OpenAI's Codex backend through a local CLIProxyAPI on 127.0.0.1:8317, billed against a ChatGPT subscription, with ANTHROPIC_BASE_URL and ANTHROPIC_AUTH_TOKEN overridden. It is the same harness — same tools, same skills — with a different model underneath.

                              That configuration needs its own rules, because behaviour differs from stock Claude Code: ENABLE_TOOL_SEARCH is off (deferred-tool discovery is unreliable on non-Claude models), tool-use concurrency is capped (the backend handles bursts poorly), and the subagent roster differs. Those rules must apply to that provider instance only — they are wrong for a stock Claude thread — and there is currently no slot for them anywhere.

                              2. The Claude provider never sees AGENTS.md.

                              Claude Code discovers CLAUDE.md, not AGENTS.md. In a repo that standardised on AGENTS.md — as this one has — a Claude thread starts with the agent unaware of the repo's own conventions, and the user re-supplies them by hand in the first message of every thread. The file is sitting in the working directory; nothing reads it.

                              Proposed solution

                              A settings list of instruction files that T3 Code reads and assembles itself, instead of delegating to provider filename conventions.

                              • Entries are paths — absolute, ~-relative, or repo-root-relative.
                              • Two scopes — global (every project) and per-project (stored with the project, so a repo's own file is picked up automatically on switch).
                              • Per-entry provider filterclaude, codex, *, or a specific provider instance. Rules written for one backend must not leak into a thread running on another.
                              • Ordered; T3 reads and concatenates. All applicable entries are read in order, joined into one payload, and handed to the provider through its native mechanism (--append-system-prompt-file for Claude, the equivalent config path for Codex; or as prefix to the first prompt in the new chat).
                              • Missing files are skipped, not fatal — with a visible note in the work log, so a typo'd path doesn't fail silently.

                              The concatenation is load-bearing, not an implementation detail: claude keeps only the last--append-system-prompt-file and silently discards earlier ones. Multiple sources can only be delivered as a single merged file.

                              Ordering and framing. When both user-level and repo-level entries are active, repo content should land after user-level content, wrapped in a short block identifying it as repository content, with the user-level rules re-asserted afterwards. A repo instruction file is third-party data — in a cloned repo it may be adversarial — and should not sit where it appears to override the user's own rules. Only whatever assembles the payload can apply that framing.

                              Why this matters

                              Anyone running a provider instance against a non-default backend needs per-instance rules, and today has nowhere to put them. If you working in an AGENTS.md repo through the Claude provider you may manually re-supplying context on every new thread.

                              Both are currently solved on my side with a shell wrapper that sits between the user and the CLI. That works from a terminal and is structurally impossible in T3 Code, because T3 Code invokes the provider itself — there is no seam for a launcher. Users who have this working in their terminal cannot bring it to the GUI, which is a concrete reason to keep a terminal open alongside T3 Code.

                              It also removes a class of silent failure. Passing the flag twice looks like it works and quietly drops the first file; a repo-relative path in a static argument string never resolves. Both fail without an error message.

                              Smallest useful scope

                              • For the Claude provider, load the repo-root AGENTS.md in addition to CLAUDE.md.
                              • For the Claudex, load the user CLAUDEX and repo-root AGENTS.md in addition to CLAUDE.md.

                              Alternatives considered

                              Launch arguments (#1971, #2892). The closest existing mechanism, and for one static absolute path it may already work. It cannot be extended to cover this:

                              1. The operation needed is file I/O, not an argument. Sources must be read from disk, concatenated, and framed before the CLI is invoked. Launch arguments are a static string; there is no read step in that path. Note that allowing repeated flags in the launch-args parser would not fix this — claude itself also keeps only the last one, so the merge is mandatory regardless of how arguments are stored.
                              2. Static strings are not interpolated against the working directory, so ./AGENTS.md cannot be expressed. Only an absolute path works, re-edited in settings on every project switch — which defeats the purpose for the most common case.
                              3. No project scope. Launch arguments belong to a provider instance, not a project.
                              4. No validation, ordering, or framing. Nothing checks the path exists or controls what lands where.

                              A wrapper script. What I use today outside T3 Code: it reads the claudex rules file and the repo's AGENTS.md, merges them into one temp file, frames the repo section as content that cannot override the rules above it, re-asserts those rules after it, passes the result via --append-system-prompt-file, refuses to launch if the rules file is missing, and rejects any user-supplied --append-system-prompt* flag that would silently replace the merged payload. Every step is file I/O and string assembly performed before the CLI starts — which is exactly why it cannot be expressed as configuration, and why it doesn't survive the move into T3 Code.

                              Symlinking AGENTS.md to CLAUDE.md. Works per-repo, pollutes the repo or the ignore file, and does nothing for problem 1.

                              Risks or tradeoffs

                              • Prompt-injection surface. Auto-loading a repo file means cloning a repo can inject text into the system prompt. This is already true of native AGENTS.md/CLAUDE.md discovery, but a configurable list widens it. Mitigated by the framing block described above, and by keeping repo-scoped entries opt-in per project.
                              • Provider divergence. Each provider has a different injection mechanism, and Codex's is config-based rather than a flag. The abstraction has to be "assemble a payload, hand it to the adapter" rather than "pass this flag."
                              • Reload semantics. If a file changes mid-thread, is it re-read? Simplest answer is no — read at session start only — but it should be a stated choice rather than an accident.
                              • Interaction with [Feature]: Session-scoped notes panel — agent-shared and user-private regions #2397 (session notes) — both inject text into the system context and should share one assembly path rather than growing two.

                              Examples or references

                              claudex setup guide (the configuration described above): https://claude.ai/code/artifact/e0a0e13e-6f60-4615-8e4b-3a8b8e3d1c41

                              Prior art for the general shape — user-specified files merged into the system prompt, with scope layering:

                              Related in this repo: #1233 (global agent prompt, single fixed file, no provider filter), #1283 / #1334 (native Claude setting sources; standard filenames only), #2397 (session-scoped notes), #1971 / #2892 (provider launch arguments, the current workaround), #737 and #1740 (adjacent prompt/skill/subagent customisation).

                              Contribution

                              • I would be open to helping implement this.

                              Metadata

                              Metadata

                              Assignees

                              No one assigned

                                Labels

                                enhancementRequested improvement or new capability.needs-triageIssue needs maintainer review and initial categorization.

                                Type

                                No type

                                Projects

                                No projects

                                  Milestone

                                  No milestone

                                  Relationships

                                  None yet

                                  Development

                                  No branches or pull requests

                                  Issue actions