SLOPSHOPPER

triflux-mods

triflux 의 Claude Code mods: HUD band 와 서브에이전트 effort 정책

newbandguardagents
★ 7v10.55.1MITupdated 2026-10-09tellang/triflux/mods/triflux
A shopper browsing a rack in a slop shop
Preview · a replayed session in a sandbox
claude · ~/work/app · triflux-mods
› fix the failing auth test and add an audit log call ⏺ Read(src/auth.ts) ⎿ Read 6 lines ⏺ Update(src/auth.ts) ⎿ Added 2 lines, removed 1 line ⏺ Bash(bun test) ⎿ 3 pass, 1 fail ● Done. refresh now rejects expired claims and logs an audit event. ✻ Worked for 42s · done 4:20 PM c 5h 31% NaNhNaNm · ctx 49% · $0.42 ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── › ? for shortcuts

Draws

Band
c 5h 31% NaNhNaNm · ctx 49% · $0.42
README

English | 한국어

<img alt="triflux" src="docs/assets/logo-dark.svg" width="200">

<h3 align="center">CLI-first multi-model orchestration for Claude Code, Codex, and Antigravity</h3>

<a href="https://www.npmjs.com/package/triflux"><img src="https://img.shields.io/npm/v/triflux?style=flat-square&color=FFAF00&label=npm" alt="npm version"></a> <a href="https://www.npmjs.com/package/triflux"><img src="https://img.shields.io/npm/dm/triflux?style=flat-square&color=F5C242" alt="npm downloads"></a> <a href="https://github.com/tellang/triflux/stargazers"><img src="https://img.shields.io/github/stars/tellang/triflux?style=flat-square&color=FFAF00" alt="GitHub stars"></a> <img src="https://img.shields.io/badge/node-%3E%3D22-374151?style=flat-square" alt="Node >= 22"> <a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/License-MIT-374151?style=flat-square" alt="License: MIT"></a>

triflux is a Claude Code plugin and npm CLI that routes coding work across Claude, Codex, and Antigravity. You describe the task once with /tfx-auto; triflux picks the CLI lane (Codex by default), runs it through managed routes instead of ad-hoc shell commands, and can fan the work out to parallel workers, live Claude↔Codex sessions, or remote hosts. Parallel code changes use separate worktrees and one session per worktree. The tfx shell CLI covers setup, diagnostics, and team orchestration.

Install

npm install -g triflux   # postinstall runs the setup script
tfx doctor               # check CLIs, tmux, MCP, profiles, skills

npm 12 and newer block install scripts by default. Allow the setup script:

npm i -g triflux --allow-scripts=triflux

Setup registers the triflux marketplace and prints a mods installation hint. To install usage bands and subagent effort enforcement (Claude Code 2.1.287 or newer):

tfx setup --mods

Or install the Claude Code plugin from this repository's marketplace:

claude plugin marketplace add tellang/triflux
claude plugin install triflux@triflux

tfx doctor --fix repairs common drift; tfx doctor --json is for automation.

First steps

/tfx-auto "fix the failing auth tests"
/tfx-auto "review this change for trust-boundary issues" --mode consensus
/tfx-auto "finish the migration and verify it" --mode deep --retry ralph --max-iterations 10

Skills

Skills you invoke directly:

SkillUse
/tfx-autoFront door for implementing, fixing, reviewing, and parallel work. Behavior is set by flags (below).
/tfx-liveLive Claude↔Codex sessions: start/ask/wait/stop, peer relay, list-sessions.
/tfx-leadLead role for running several Claude/Codex sessions: roles and models, briefs, cross review, merge and release coordination.
/tfx-remoteRemote Claude Code sessions over SSH: start, list, reattach, send, readiness probe, monitor, stop.
/tfx-setupSetup: file sync, HUD, Codex and Antigravity profiles, MCP. tfx setup --mods installs mods.
/tfx-doctorDiagnose and repair.
/tfx-shiptriflux release flow (maintainers).
/tfx-wtWindows Terminal tabs and panes. tfx setup installs it on Windows only.

Internal lanes (marked internal: true; other skills and the router call them, but you can name them explicitly):

SkillUse
tfx-harnessMeta routing: returns which skill or path fits a request, without running it.
tfx-reviewCode review verdict (--quick for a lighter pass).
tfx-researchWeb research with cross-checked sources (--quick, --auto, --depth).

Use superpowers writing-plans for implementation plans, host deep-interview for requirements, and Claude Code’s built-in /goal for goals. Use /tfx-auto --mode deep for multi-model planning and execution. Manage Codex profiles directly in ~/.codex/<profile>.config.toml.

/tfx-auto flags

FlagValuesEffect
--modequick (default), deep, consensus, livedeep = plan → execute → verify loop; consensus = multi-CLI agreement; live = hand off to tfx-live peer
--shapeconsensus, debate, panelOutput shape for --mode consensus
--cliauto, codex, antigravity, claudeForce a CLI lane
--cli-settriad, no-antigravity, customConsensus participants
--parallel1, NN = local workers (tfx multi)
--retry0, 1 (default), ralph, auto-escalateralph = retry state machine with stuck detection; auto-escalate = move up the model chain
--max-iterationsNCap for ralph / auto-escalate (0 = unlimited)
--roundsN (default 4)Round trips for --mode live
--skill<name>Prepend skills/<name>/SKILL.md to the Codex/Antigravity prompt
--no-native-bridge-uiHide headless workers from the claude agents panel

The full contract, including --lead, --options, --experts, and conflict rules, lives in skills/tfx-auto/SKILL.md.

Models and profiles

Codex runs through named profiles; model IDs live in ~/.codex/<profile>.config.toml, and the role → profile map lives in scripts/lib/agent-route-policy.mjs. Claude is called by alias, so the newest model in each tier is picked up automatically.

Profile / aliasLanes
gpt6_astra_xhighArchitecture, planning, critique, debugging, security review, deep execution
gpt6_astra_max, gpt6_astra_ultraHardest single tasks (`TFX_CODEX_PROFILE=max\ultra); max is the first auto-escalate` step
gpt61_sol_high / gpt61_sol_medDefault implementation, review, verification, tests, docs / cleanup
gpt6_luna_high / gpt6_luna_lowBuild fixes, writing / latency-first lookups
Claude fableFinal --retry auto-escalate step
Claude opus / sonnet / haikuMeta routing and planning gates / Claude-native QA and verification / fast exploration

Routing policy: .claude/rules/tfx-routing.md · escalation chain: .claude/rules/tfx-escalation-chain.md.

Shell CLI

CommandUse
tfx setup / tfx doctorSync files, HUD, MCP, profiles / diagnose and repair (--fix, --json)
tfx multiLocal multi-CLI team in tmux
tfx mcpManaged MCP registry: list, sync, add, remove
bash ~/.claude/scripts/tfx-route.sh code-reviewer "<instruction>"Send review to Codex (codex exec review via policy)
tfx list, tfx update, tfx versionInstalled skills, update, version
tfx-liveLive session bridge (same as the /tfx-live skill)

tfx <command> --help prints the exact arguments.

Runtime features

Live sessions. tfx-live drives Claude Code and Codex TUI sessions. Claude daemon targets (--short/--session-id) try UDS first and fall back to tmux when --session is also given; Codex ask queues the message through the app-server thread/queue/add API (shown in the TUI with a [from <sender>] first line) and falls back to tmux with a reported reason; UDS stays available with --transport uds --thread <id|auto>. peer relays between two sessions for --rounds. triflux's Codex hook records running Codex sessions under ~/.local/state/triflux/codex-sessions/, so tfx-live list-sessions --cli codex|claude also finds sessions you started yourself in tmux.

Long jobs. scripts/tfx-route.sh --async <agent> "<prompt>" returns a job id at once, which gets past Claude Code's 600-second Bash limit. Follow up with --job-status, --job-wait, and --job-result.

Headless workers. Workers from tfx-auto and tfx multi appear in the claude agents panel unless you pass --no-native-bridge-ui. Press Enter on a row to open the tmux pane the worker runs in.

Retry and escalation. --retry ralph loops until done or stuck (three identical failures). --retry auto-escalate steps from Codex gpt6_astra_max to Claude fable; override the chain in .triflux/config/escalation-chain.json.

Machine profile. Setup records which CLIs this machine may use and its timeout policy in ~/.config/triflux/machine-profile.env. TFX_DISABLE_CODEX=1 or TFX_DISABLE_ANTIGRAVITY=1 removes a CLI from routing; if no allowed CLI is available the route fails instead of silently falling back. Details: .claude/rules/tfx-machine-profile.md.

Remote hosts. /tfx-remote reads hosts from ~/.config/triflux/hosts.json (Windows: %APPDATA%\triflux\hosts.json). Start a session with remote-spawn.mjs --host <host> --prompt "<request>". Options: skills/tfx-remote/SKILL.md.

Architecture

graph TD
    User([Claude Code prompt / shell]) --> Skills["/tfx-auto · /tfx-live · /tfx-remote"]
    User --> Lead["/tfx-lead"]
    User --> CLI[tfx CLI]
    Lead -->|"briefs, cross review, merge"| Live
    Skills --> Route[tfx-route.sh]
    Skills --> Live[tfx-live]
    CLI --> Team["tfx multi"]
    Route --> Codex[Codex CLI]
    Route --> Agy[Antigravity agy]
    Route --> Claude[Claude Code]
    Team -->|headless workers| Route
    Team --> Index[("results index: tfx-headless/*.results.json")]
    Team --> Rows["claude agents rows"]
    Rows -->|Enter| Room["worker tmux room"]
    Live -->|"codex queue, tmux fallback"| CodexTUI[Codex TUI sessions]
    Live -->|"UDS or tmux"| ClaudeTUI[Claude Code sessions]
    Route --> HUD[HUD]

Package layout and execution paths: ARCHITECTURE.md. Documentation map: docs/README.md.

Platforms

PlatformMultiplexerNotes
macOStmuxDefault path. Install coreutils (gtimeout) if you keep a positive hard ceiling.
LinuxtmuxSupported.
Windowspsmux + Windows TerminalSee below.

Windows. psmux (a tmux fork) runs PowerShell by default. Callers do not run wt.exe or raw psmux kill-session directly; tabs and panes go through the tfx-wt skill (set up only on Windows) and hub/team/wt-manager.mjs. Agent rules: .claude/rules/tfx-psmux.md.

Security and guards

LayerProtection
Managed routesCodex and Antigravity are called through tfx-route.sh, headless workers, or tfx, never through a bare codex exec or agy. This is a rule for callers; no hook enforces it.
MCP registryReplaces stale or unsupported MCP entries with managed ones.
ConsensusDeep and consensus runs report degraded or disputed results instead of hiding them.

Contributing

Node 22 or newer. See CONTRIBUTING.md for tests, lint, package boundaries, mirror and release checks, and state snapshots. Releases are automated: merging a version-bump commit to main runs release.yml after CI passes; it tags, creates the GitHub release, and publishes to npm through OIDC Trusted Publishing. Decisions are recorded in docs/adr/.

<sub>MIT License &middot; Made by <a href="https://github.com/tellang">tellang</a></sub>

Source 4 files
hooks/register.ts 10 lines
1import type { Register } from 'claude-code'
2
3import { registerAgentEffort } from './agent-effort.ts'
4import { registerHudBand } from './hud-band.tsx'
5
6export const register: Register = on => {
7  registerHudBand(on)
8  registerAgentEffort(on)
9}
10
hooks/agent-effort.ts 61 lines
1import type { On } from 'claude-code'
2
3type Effort = 'low' | 'medium' | 'high'
4
5// effort 없이 부른 서브에이전트는 부모 effort 를 물려받는다(2.1.292 실측). 탐색은 낮게, 판정은 높게 고정한다.
6const EFFORT_BY_AGENT: Record<string, Effort> = {
7  Explore: 'low',
8  'oh-my-claudecode:explore': 'low',
9  'general-purpose': 'medium',
10  'oh-my-claudecode:executor': 'medium',
11  'oh-my-claudecode:test-engineer': 'medium',
12  'oh-my-claudecode:writer': 'medium',
13  Plan: 'high',
14  'oh-my-claudecode:architect': 'high',
15  'oh-my-claudecode:analyst': 'high',
16  'oh-my-claudecode:critic': 'high',
17  'oh-my-claudecode:planner': 'high',
18  'oh-my-claudecode:code-reviewer': 'high',
19  'oh-my-claudecode:security-reviewer': 'high',
20  'oh-my-claudecode:verifier': 'high',
21  'oh-my-claudecode:debugger': 'high',
22  'oh-my-claudecode:tracer': 'high',
23}
24
25export function registerAgentEffort(on: On) {
26  const explicitCalls = new Set<string>()
27  const effortByAgentId = new Map<string, Effort>()
28
29  on('tool.call', { tool: 'Agent' }, async ($, e, next) => {
30    if (!e.effort) return next(e)
31    explicitCalls.add(e.tool_use_id)
32    try {
33      return await next(e)
34    } finally {
35      explicitCalls.delete(e.tool_use_id)
36    }
37  })
38
39  on('agent.spawn', async ($, e, next) => {
40    const spawned = await next(e)
41    const effort = EFFORT_BY_AGENT[e.subagentType]
42    // 호출자가 Agent 도구에 effort 를 직접 적었으면 그 값을 따른다.
43    if (spawned.agentId && effort && !e.fork && !explicitCalls.has(e.tool_use_id))
44      effortByAgentId.set(spawned.agentId, effort)
45    return spawned
46  })
47
48  // /clear 는 session.start 없이 새 세션으로 넘어가므로 여기서 비운다.
49  on('session.end', ($, e, next) => {
50    explicitCalls.clear()
51    effortByAgentId.clear()
52    return next(e)
53  })
54
55  on('turn.step', async function* ($, e, next) {
56    const effort = e.agentId ? effortByAgentId.get(e.agentId) : undefined
57    // effort 가 없는 모델(Haiku 등)은 건드리지 않는다.
58    return yield* next(effort && e.effort !== undefined ? { ...e, effort } : e)
59  })
60}
61
hooks/hud-band.tsx 76 lines
1import { atom, read, update } from 'claude-code'
2import type { EngineInterface, On } from 'claude-code'
3
4import type { UsageSnapshot, UsageWindow } from '../types'
5
6const usage = atom({ plugin: 'triflux-mods', key: 'usage' } as const, null)
7
8const WINDOW_LABEL: Record<string, string> = { five_hour: '5h', seven_day: '1w', spend_limit: '$' }
9
10// 선택 기능이라 실패를 삼킨다. hook 오류가 쌓이면 mod 전체가 꺼진다.
11async function refreshUsage($: EngineInterface) {
12  try {
13    const { rateLimits, context, cost } = await $.session.usage()
14    const snapshot: UsageSnapshot = {
15      windows: rateLimits.map(({ kind, percentUsed, resetsAt }) => ({ kind, percentUsed, resetsAt })),
16      contextPercent: context.percent ?? null,
17      costUsd: cost?.usd ?? null,
18    }
19    await update($, usage, () => snapshot)
20    // band 가 실제로 그려질 때만 statusLine HUD 가 Claude 행을 뺀다(hud/hud-qos-status.mjs).
21    const home = await $.env.get('HOME')
22    if (home && snapshot.windows.length > 0)
23      await $.fs.write(`${home}/.claude/cache/triflux/claude-band/${await $.session.id()}`, String(await $.clock.now()))
24  } catch {}
25}
26
27function formatRemaining(resetsAt: string | undefined, now: number) {
28  if (!resetsAt) return ''
29  const minutes = Math.max(0, Math.round((Date.parse(resetsAt) - now) / 60000))
30  const days = Math.floor(minutes / 1440)
31  const hours = Math.floor((minutes % 1440) / 60)
32  return days > 0 ? `${days}d${String(hours).padStart(2, '0')}h` : `${hours}h${String(minutes % 60).padStart(2, '0')}m`
33}
34
35function percentColor(percent: number) {
36  return percent >= 80 ? 'error' : percent >= 50 ? 'warning' : undefined
37}
38
39export function registerHudBand(on: On) {
40  on('session.start', async ($, e, next) => {
41    await refreshUsage($)
42    return next(e)
43  })
44
45  // 응답이 끝날 때마다 rate limit 과 비용이 바뀐다.
46  on('turn.complete', async ($, e, next) => {
47    const result = await next(e)
48    await refreshUsage($)
49    return result
50  })
51
52  on('ui.render', { component: 'AbovePrompt' }, async ($, e, next) => {
53    const snapshot = await read($, usage)
54    if (e.props.hasSurvey || !snapshot || snapshot.windows.length === 0) return next(e)
55
56    const { Box, Text } = $.ui.resolve(e)
57    const now = await $.clock.now()
58    const windowText = (w: UsageWindow) =>
59      `${WINDOW_LABEL[w.kind] ?? w.kind} ${Math.round(w.percentUsed)}% ${formatRemaining(w.resetsAt, now)}`.trimEnd()
60
61    return (
62      <Box>
63        <Text dimColor>c </Text>
64        {snapshot.windows.map((w, i) => (
65          <Text color={percentColor(w.percentUsed)} dimColor={!percentColor(w.percentUsed)}>
66            {i > 0 ? ' · ' : ''}
67            {windowText(w)}
68          </Text>
69        ))}
70        {snapshot.contextPercent !== null && <Text dimColor> · ctx {snapshot.contextPercent}%</Text>}
71        {snapshot.costUsd !== null && <Text dimColor> · ${snapshot.costUsd.toFixed(2)}</Text>}
72      </Box>
73    )
74  })
75}
76
types/index.d.ts 14 lines
1export type UsageWindow = { kind: string; percentUsed: number; resetsAt?: string }
2
3export type UsageSnapshot = {
4  windows: UsageWindow[]
5  contextPercent: number | null
6  costUsd: number | null
7}
8
9declare module 'claude-code' {
10  interface PluginState {
11    'triflux-mods': { usage: UsageSnapshot | null }
12  }
13}
14