Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ bin/gstack-global-discover
.cursor/
.openclaw/
.hermes/
.gemini/
.gbrain/
.gbrain-source
.context/
Expand All @@ -37,3 +38,8 @@ supabase/.temp/

# Throughput analysis — local-only, regenerate via scripts/garry-output-comparison.ts
docs/throughput-*.json

# Local tool/skill artifacts and unrelated nested projects (never part of gstack source)
.serena/
graphify-out/
shopify-oauth/
70 changes: 70 additions & 0 deletions hosts/gemini.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import type { HostConfig } from '../scripts/host-config';

const gemini: HostConfig = {
name: 'gemini',
displayName: 'Gemini CLI',
cliCommand: 'gemini',
cliAliases: ['gemini-cli'],

globalRoot: '.gemini/skills/gstack',
localSkillRoot: '.gemini/skills/gstack',
hostSubdir: '.gemini',
usesEnvVars: true,

frontmatter: {
mode: 'allowlist',
keepFields: ['name', 'description'],
descriptionLimit: null,
},

generation: {
generateMetadata: false,
skipSkills: ['codex'],
},

pathRewrites: [
{ from: '~/.claude/skills/gstack', to: '~/.gemini/skills/gstack' },
{ from: '.claude/skills/gstack', to: '.gemini/skills/gstack' },
{ from: '.claude/skills', to: '.gemini/skills' },
{ from: 'CLAUDE.md', to: 'GEMINI.md' },
],

toolRewrites: {
'use the Bash tool': 'use the run_shell_command tool',
'use the Write tool': 'use the write_file tool',
'use the Read tool': 'use the read_file tool',
'use the Edit tool': 'use the replace_in_file tool',
'use the Agent tool': 'use delegate_to_agent',
'use the Glob tool': 'use the list_directory tool',
'use the Grep tool': 'use the search_files tool',
'the Bash tool': 'the run_shell_command tool',
'the Read tool': 'the read_file tool',
'the Write tool': 'the write_file tool',
'the Edit tool': 'the replace_in_file tool',
},

suppressedResolvers: [
'DESIGN_OUTSIDE_VOICES',
'ADVERSARIAL_STEP',
'CODEX_SECOND_OPINION',
'CODEX_PLAN_REVIEW',
'REVIEW_ARMY',
],

runtimeRoot: {
globalSymlinks: ['bin', 'browse/dist', 'browse/bin', 'gstack-upgrade', 'ETHOS.md'],
globalFiles: {
'review': ['checklist.md', 'TODOS-format.md'],
},
},

install: {
prefixable: false,
linkingStrategy: 'symlink-generated',
},

coAuthorTrailer: 'Co-Authored-By: Gemini CLI <noreply@google.com>',
learningsMode: 'basic',
};

export default gemini;
5 changes: 3 additions & 2 deletions hosts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ import cursor from './cursor';
import openclaw from './openclaw';
import hermes from './hermes';
import gbrain from './gbrain';
import gemini from './gemini';

/** All registered host configs. Add new hosts here. */
export const ALL_HOST_CONFIGS: HostConfig[] = [claude, codex, factory, kiro, opencode, slate, cursor, openclaw, hermes, gbrain];
export const ALL_HOST_CONFIGS: HostConfig[] = [claude, codex, factory, kiro, opencode, slate, cursor, openclaw, hermes, gbrain, gemini];

/** Map from host name to config. */
export const HOST_CONFIG_MAP: Record<string, HostConfig> = Object.fromEntries(
Expand Down Expand Up @@ -65,4 +66,4 @@ export function getExternalHosts(): HostConfig[] {
}

// Re-export individual configs for direct import
export { claude, codex, factory, kiro, opencode, slate, cursor, openclaw, hermes, gbrain };
export { claude, codex, factory, kiro, opencode, slate, cursor, openclaw, hermes, gbrain, gemini };
4 changes: 2 additions & 2 deletions test/host-config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ const ROOT = path.resolve(import.meta.dir, '..');
// ─── hosts/index.ts ─────────────────────────────────────────

describe('hosts/index.ts', () => {
test('ALL_HOST_CONFIGS has 10 hosts', () => {
expect(ALL_HOST_CONFIGS.length).toBe(10);
test('ALL_HOST_CONFIGS has 11 hosts', () => {
expect(ALL_HOST_CONFIGS.length).toBe(11);
});

test('ALL_HOST_NAMES matches config names', () => {
Expand Down