Skip to content

feat(cli): add Grok Build CLI tool setup (~/.grok/config.toml) - #7241

Merged
diegosouzapw merged 5 commits into
release/v3.8.49from
feat/port-pr-2571-grok-build-setup
Jul 17, 2026
Merged

diegosouzapw merged 5 commits into
release/v3.8.49from
feat/port-pr-2571-grok-build-setup

Conversation

@diegosouzapw

Copy link
Copy Markdown
Owner

Summary

Attribution

Thanks to @rixzkiye for the original implementation this port is based on.

Changes

  • src/app/api/cli-tools/grok-build-settings/route.ts (new) — GET/POST/DELETE handler.
  • src/shared/constants/cliTools.ts — grok-build entry (configType: "custom", category code).
  • src/shared/services/cliRuntime.ts — runtime descriptor (grok binary, .grok/config.toml, CLI_GROK_BUILD_BIN).
  • src/server/authz/routeGuard.ts — classify the route local-only.
  • docs/reference/CLI-TOOLS.md — tool table + settings-handler table rows.
  • Tests: 1 integration file + 1 route-guard unit file.

Implementation notes

Grok Build's config can hold several user-defined [model.*] sections plus a [models].default pointer. Unlike the sibling Forge handler (which owns its whole config file and full-replaces it), this handler surgically upserts only the [model.omniroute] section, leaving every other section byte-intact — covered by an explicit test asserting a pre-existing [model.custom-thing] survives both Apply and Reset.

Apply records the prior default in an # omniroute-prev-default = "..." marker so Reset restores the user's original default rather than guessing.

Rebuilt on OmniRoute's existing CLI-tools infrastructure instead of replaying the upstream shape: getCliRuntimeStatus() for detection (no ad-hoc which grok exec — Hard Rule #13), cliModelConfigSchema Zod validation, the write guard, createBackup(), the cliToolState DB module, and sanitizeErrorMessage() on every error path (Hard Rule #12).

Security

GET reaches getCliRuntimeStatus(), which spawns a child process to locate and healthcheck the grok binary. That is the same transitive-spawn surface that classified /api/skills/collect/, and the same class as the already-gated omp-settings / letta-settings. The route is therefore added to LOCAL_ONLY_API_PREFIXES so loopback enforcement runs before any auth check — a leaked JWT over a tunnel cannot trigger the spawn. Writing a local CLI's config file is inherently a local-machine operation, so loopback-only costs no real capability. A unit test asserts isLocalOnlyPath() returns true for it, and that the entry does not over-gate the rest of /api/cli-tools/.

Test plan

  • tests/unit/route-guard-grok-build-settings-local-only.test.ts — 4/4 pass. Fails before the routeGuard entry (verified: 2 assertions ✖), passes after.
  • tests/integration/cli-settings-grok-build.test.ts — 9/9 pass (auth 401, Zod 400s, Apply preserves unrelated sections + records prev-default, Reset restores it, no-op DELETE, error sanitization, no exec()/spawn()).
  • tests/unit/check-route-guard-membership.test.ts — 15/15 pass (new prefix does not break the gate).
  • npm run typecheck:core — clean.
  • npx eslint <changed files> — clean.

Registers xAI's Grok Build TUI coding agent as a configurable CLI tool in
/dashboard/cli-code, so OmniRoute can write itself in as a custom model
provider in ~/.grok/config.toml.

Mechanism: Grok Build reads a TOML config that can hold several user-defined
[model.*] sections plus a [models].default pointer. Unlike the sibling Forge
handler (which owns its whole config file and can full-replace it), this one
surgically upserts ONLY the [model.omniroute] section and rewrites
[models].default, leaving every other section byte-intact. Apply records the
previous default in an `# omniroute-prev-default` marker comment so Reset can
restore the user's original default instead of guessing.

Built on OmniRoute's existing CLI-tools infrastructure rather than replaying
the upstream shape: getCliRuntimeStatus() for detection (no ad-hoc
`which grok` exec), Zod validation via cliModelConfigSchema, the write guard,
createBackup(), the cliToolState DB module, and sanitizeErrorMessage() for
every error path (Hard Rule #12).

Security: GET reaches getCliRuntimeStatus(), which spawns a child process to
locate and healthcheck the `grok` binary. That is the same transitive-spawn
surface that classified /api/skills/collect/, so the route is registered in
LOCAL_ONLY_API_PREFIXES and loopback-enforced before any auth check
(Hard Rules #15 + #17). Writing a local CLI's config file is inherently a
local-machine operation, so this costs no real capability.

Co-authored-by: rixzkiye <rizkiyemubarok05@gmail.com>
Inspired-by: decolua/9router#2571
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@diegosouzapw

Copy link
Copy Markdown
Owner Author

Revisado a fundo — implementação sólida e bem alinhada com o padrão já estabelecido (omp-settings/letta-settings). Pontos verificados especificamente: (1) classificação LOCAL_ONLY correta e comprovada por teste — GET realmente spawna processo via getCliRuntimeStatus (confirmei no cliRuntime.ts); (2) upsert cirúrgico da seção [model.omniroute] preserva outras seções [model.*] do usuário (testado com pre-seed de [model.custom-thing]); (3) Reset restaura o default anterior via o marcador de comentário, e é no-op seguro quando não há config. Revert-proof da regressão de segurança confirmado (teste cai sem a entrada em LOCAL_ONLY_API_PREFIXES). typecheck+eslint limpos. Pronto para merge.

…t + fix stale catalog counts

The grok-build registry/runtime entries pushed cliTools.ts (916->932) and
cliRuntime.ts (1128->1137) past their frozen file-size caps. Extract the
grok-build entries into cliToolsGrokBuild.ts (registry, typed) and
cliRuntimeGrokBuild.ts (runtime metadata, deliberately untyped/no
cliCatalog import so it doesn't drag that schema file into the
typecheck:core curated allowlist's transitive graph). The amp runtime
entry rides along in the same runtime file for the extra headroom needed
to clear cliRuntime.ts's cap with zero slack.

Also update the two catalog-cardinality canaries (cli-tools-schema.test.ts,
cli-catalog-counts.test.ts) and EXPECTED_CODE_COUNT to include grok-build:
20->21 visible code entries, 24->25 total code entries, 32->33 grand total.

Fixes CI reds on #7241 surviving a release/v3.8.49 merge: Fast Quality
Gates (check:file-size) and Unit Tests fast-path (1/4, 2/4).
check:mutation-test-coverage --strict flagged
tests/unit/route-guard-grok-build-settings-local-only.test.ts as a covering
unit test for src/server/authz/routeGuard.ts missing from
stryker.conf.json's tap.testFiles allowlist (only became reachable once the
Fast Quality Gates job got past the file-size fix earlier in this branch).
@diegosouzapw

Copy link
Copy Markdown
Owner Author

Babysit summary

Stale verdict refresh: PR was 45 commits behind release/v3.8.49. Merged the base in (clean, no conflicts) and pushed — this alone re-triggered a fresh CI run.

Real defects found and fixed (survived the fresh run):

  • Fast Quality Gates → check:file-size: the grok-build registry/runtime entries pushed src/shared/constants/cliTools.ts (916→932) and src/shared/services/cliRuntime.ts (1128→1137) past their frozen file-size ratchet caps (both files had zero slack at the cap). Fixed by extracting the new entries into src/shared/constants/cliToolsGrokBuild.ts (typed registry entry) and src/shared/services/cliRuntimeGrokBuild.ts (untyped runtime metadata, deliberately without a CliCatalogEntry import so it doesn't drag src/shared/schemas/cliCatalog.ts into typecheck:core's curated transitive graph). The pre-existing amp runtime entry rides along in the same runtime file to make up the last bit of headroom. (e1da792de)
  • Unit Tests fast-path (1/4) (tests/unit/cli-tools-schema.test.ts) and (2/4) (tests/unit/cli-catalog-counts.test.ts): stale hardcoded cardinality canaries — grok-build is a new visible code entry, so the registry grew 32→33 total / 20→21 visible-code / 24→25 total-code. Updated the expected lists/counts and EXPECTED_CODE_COUNT (20→21) in src/shared/schemas/cliCatalog.ts to match. (e1da792de)
  • Once check:file-size was unblocked, the same job reached check:mutation-test-coverage --strict for the first time and flagged tests/unit/route-guard-grok-build-settings-local-only.test.ts as missing from stryker.conf.json's tap.testFiles. Registered it. (32d00087f)

Verification: all touched files pass lint + typecheck:core cleanly; ran the full affected local test set (cli-tools-schema, cli-catalog-counts, cli-runtime*, cli-catalog-removed, cli-tools, the grok-build integration + route-guard tests) — 71 tests, all green; ran every check:* gate in the Fast Quality Gates job locally before pushing.

Result: all CI checks green (Fast Quality Gates, Unit Tests fast-path 1-4, Vitest, Docs Gates, ESLint, dast-smoke, semgrep ×2, merge integrity, change classification). No review threads were open. No test assertion was weakened — the two count-based tests were updated to the new, correct cardinalities, and the mutation-coverage fix only registers an existing test in the allowlist.

Ready for human review & merge.

@diegosouzapw
diegosouzapw merged commit 624aba2 into release/v3.8.49 Jul 17, 2026
15 checks passed
@diegosouzapw
diegosouzapw deleted the feat/port-pr-2571-grok-build-setup branch July 19, 2026 21:00
HouMinXi pushed a commit to HouMinXi/OmniRoute that referenced this pull request Aug 2, 2026
…souzapw#7241)

* feat(cli): add Grok Build CLI tool setup (~/.grok/config.toml)

Registers xAI's Grok Build TUI coding agent as a configurable CLI tool in
/dashboard/cli-code, so OmniRoute can write itself in as a custom model
provider in ~/.grok/config.toml.

Mechanism: Grok Build reads a TOML config that can hold several user-defined
[model.*] sections plus a [models].default pointer. Unlike the sibling Forge
handler (which owns its whole config file and can full-replace it), this one
surgically upserts ONLY the [model.omniroute] section and rewrites
[models].default, leaving every other section byte-intact. Apply records the
previous default in an `# omniroute-prev-default` marker comment so Reset can
restore the user's original default instead of guessing.

Built on OmniRoute's existing CLI-tools infrastructure rather than replaying
the upstream shape: getCliRuntimeStatus() for detection (no ad-hoc
`which grok` exec), Zod validation via cliModelConfigSchema, the write guard,
createBackup(), the cliToolState DB module, and sanitizeErrorMessage() for
every error path (Hard Rule diegosouzapw#12).

Security: GET reaches getCliRuntimeStatus(), which spawns a child process to
locate and healthcheck the `grok` binary. That is the same transitive-spawn
surface that classified /api/skills/collect/, so the route is registered in
LOCAL_ONLY_API_PREFIXES and loopback-enforced before any auth check
(Hard Rules diegosouzapw#15 + diegosouzapw#17). Writing a local CLI's config file is inherently a
local-machine operation, so this costs no real capability.

Co-authored-by: rixzkiye <rizkiyemubarok05@gmail.com>
Inspired-by: decolua/9router#2571

* chore(changelog): fragment for diegosouzapw#7241

* fix(cli): shrink cliTools.ts/cliRuntime.ts under the file-size ratchet + fix stale catalog counts

The grok-build registry/runtime entries pushed cliTools.ts (916->932) and
cliRuntime.ts (1128->1137) past their frozen file-size caps. Extract the
grok-build entries into cliToolsGrokBuild.ts (registry, typed) and
cliRuntimeGrokBuild.ts (runtime metadata, deliberately untyped/no
cliCatalog import so it doesn't drag that schema file into the
typecheck:core curated allowlist's transitive graph). The amp runtime
entry rides along in the same runtime file for the extra headroom needed
to clear cliRuntime.ts's cap with zero slack.

Also update the two catalog-cardinality canaries (cli-tools-schema.test.ts,
cli-catalog-counts.test.ts) and EXPECTED_CODE_COUNT to include grok-build:
20->21 visible code entries, 24->25 total code entries, 32->33 grand total.

Fixes CI reds on diegosouzapw#7241 surviving a release/v3.8.49 merge: Fast Quality
Gates (check:file-size) and Unit Tests fast-path (1/4, 2/4).

* test(stryker): register grok-build route-guard test in tap.testFiles

check:mutation-test-coverage --strict flagged
tests/unit/route-guard-grok-build-settings-local-only.test.ts as a covering
unit test for src/server/authz/routeGuard.ts missing from
stryker.conf.json's tap.testFiles allowlist (only became reachable once the
Fast Quality Gates job got past the file-size fix earlier in this branch).

---------

Co-authored-by: rixzkiye <rizkiyemubarok05@gmail.com>
muhamadgalihsaputra pushed a commit to niyatna/NiyatnaRoute that referenced this pull request Sep 27, 2026
…souzapw#7241)

* feat(cli): add Grok Build CLI tool setup (~/.grok/config.toml)

Registers xAI's Grok Build TUI coding agent as a configurable CLI tool in
/dashboard/cli-code, so OmniRoute can write itself in as a custom model
provider in ~/.grok/config.toml.

Mechanism: Grok Build reads a TOML config that can hold several user-defined
[model.*] sections plus a [models].default pointer. Unlike the sibling Forge
handler (which owns its whole config file and can full-replace it), this one
surgically upserts ONLY the [model.omniroute] section and rewrites
[models].default, leaving every other section byte-intact. Apply records the
previous default in an `# omniroute-prev-default` marker comment so Reset can
restore the user's original default instead of guessing.

Built on OmniRoute's existing CLI-tools infrastructure rather than replaying
the upstream shape: getCliRuntimeStatus() for detection (no ad-hoc
`which grok` exec), Zod validation via cliModelConfigSchema, the write guard,
createBackup(), the cliToolState DB module, and sanitizeErrorMessage() for
every error path (Hard Rule diegosouzapw#12).

Security: GET reaches getCliRuntimeStatus(), which spawns a child process to
locate and healthcheck the `grok` binary. That is the same transitive-spawn
surface that classified /api/skills/collect/, so the route is registered in
LOCAL_ONLY_API_PREFIXES and loopback-enforced before any auth check
(Hard Rules diegosouzapw#15 + diegosouzapw#17). Writing a local CLI's config file is inherently a
local-machine operation, so this costs no real capability.

Co-authored-by: rixzkiye <rizkiyemubarok05@gmail.com>
Inspired-by: decolua/9router#2571

* chore(changelog): fragment for diegosouzapw#7241

* fix(cli): shrink cliTools.ts/cliRuntime.ts under the file-size ratchet + fix stale catalog counts

The grok-build registry/runtime entries pushed cliTools.ts (916->932) and
cliRuntime.ts (1128->1137) past their frozen file-size caps. Extract the
grok-build entries into cliToolsGrokBuild.ts (registry, typed) and
cliRuntimeGrokBuild.ts (runtime metadata, deliberately untyped/no
cliCatalog import so it doesn't drag that schema file into the
typecheck:core curated allowlist's transitive graph). The amp runtime
entry rides along in the same runtime file for the extra headroom needed
to clear cliRuntime.ts's cap with zero slack.

Also update the two catalog-cardinality canaries (cli-tools-schema.test.ts,
cli-catalog-counts.test.ts) and EXPECTED_CODE_COUNT to include grok-build:
20->21 visible code entries, 24->25 total code entries, 32->33 grand total.

Fixes CI reds on diegosouzapw#7241 surviving a release/v3.8.49 merge: Fast Quality
Gates (check:file-size) and Unit Tests fast-path (1/4, 2/4).

* test(stryker): register grok-build route-guard test in tap.testFiles

check:mutation-test-coverage --strict flagged
tests/unit/route-guard-grok-build-settings-local-only.test.ts as a covering
unit test for src/server/authz/routeGuard.ts missing from
stryker.conf.json's tap.testFiles allowlist (only became reachable once the
Fast Quality Gates job got past the file-size fix earlier in this branch).

---------

Co-authored-by: rixzkiye <rizkiyemubarok05@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant