Skip to content
Closed
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
2 changes: 1 addition & 1 deletion Bundles/Kai/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ bun run install.ts --update
### Fresh Install

The wizard will:
1. **Detect existing AI systems** - Scans for Claude Code, Cursor, Windsurf, Cline, Aider, Continue
1. **Detect existing AI systems** - Scans for Claude Code, Gemini CLI, Cursor, Windsurf, Cline, Aider, Continue
2. **Show you what it found** and explain what will be backed up
3. **Ask for your confirmation** before making any changes
4. **Create a safety backup** of your existing `~/.claude` directory to `~/.claude-BACKUP`
Expand Down
773 changes: 509 additions & 264 deletions Bundles/Kai/install.ts

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Packs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ The old approach was "here's my whole system—clone it and customize." That cre
**Packs are different:**
- **Self-contained** - Works without understanding the rest of the system
- **Independently installable** - Add what you need, skip what you don't
- **Platform-agnostic** - Works with Claude Code, OpenCode, Cursor, or custom systems
- **Platform-agnostic** - Works with Claude Code, Gemini CLI, OpenCode, Cursor, or custom systems
- **AI-installable** - Give your AI the pack directory, it handles the rest

**The key insight:** Give your AI the complete context it needs, and it can integrate the pack into *your* system autonomously.
Expand Down
5 changes: 5 additions & 0 deletions Packs/kai-core-install/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ keywords: [core, identity, skills, routing, architecture, installation, foundati

> The complete foundation for Personal AI Infrastructure - skill routing, identity framework, and architecture tracking in one unified pack.

## Platform Compatibility

- **Claude Code**: Full native support.
- **Gemini CLI**: Supported via the `gemini-pai` adapter, which provides context injection and hook simulation.

## What This Pack Provides

**Part 1: Skill System**
Expand Down
2 changes: 2 additions & 0 deletions Packs/kai-core-install/src/skills/CORE/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,12 @@ User: "What's Angela's email?"
**Assistant:**
- Name: [YOUR_AI_NAME]
- Role: [YOUR_NAME]'s AI assistant
- Operating Environment: Personal AI infrastructure built on Claude Code / Gemini CLI

**User:**
- Name: [YOUR_NAME]
- Profession: [YOUR_PROFESSION]
- Email: [YOUR_EMAIL]

---

Expand Down
5 changes: 5 additions & 0 deletions Packs/kai-history-system/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ keywords: [history, documentation, memory, capture, hooks, sessions, learnings,

> Granular context-tracking system for the entire AI infrastructure - captures all work, decisions, and learnings automatically with zero manual effort

## Platform Compatibility

- **Claude Code**: Full native support via `settings.json` hooks.
- **Gemini CLI**: Supported via the `gemini-pai` adapter, which simulates the hook lifecycle (SessionStart and Stop).

## What's Included

| Component | File | Purpose |
Expand Down
5 changes: 5 additions & 0 deletions Packs/kai-hook-system/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ keywords: [hooks, automation, events, security, validation, sessions, context, c

> Event-driven automation framework for Claude Code - the foundation for all hook-based capabilities

## Platform Compatibility

- **Claude Code**: Full native support via `settings.json` hooks.
- **Gemini CLI**: Supported via the `gemini-pai` adapter, which simulates the hook lifecycle (SessionStart and Stop).

## What's Included

| Component | File | Purpose |
Expand Down
9 changes: 6 additions & 3 deletions Packs/kai-hook-system/src/initialize-session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,13 @@ function getProjectName(cwd: string | undefined): string {
}

async function checkForUpdates(): Promise<void> {
// Optional: Check for Claude Code updates in background
// Optional: Check for AI system updates in background
// This is non-blocking and fails silently
const sourceApp = (process.env.PAI_SOURCE_APP || '').toLowerCase();
const binary = sourceApp.includes('gemini') ? 'gemini' : 'claude';

try {
const proc = Bun.spawn(['claude', '--version'], {
const proc = Bun.spawn([binary, '--version'], {
stdout: 'pipe',
stderr: 'pipe'
});
Expand All @@ -74,7 +77,7 @@ async function checkForUpdates(): Promise<void> {
if (version) {
// Could compare against known latest version
// For now, just log it
console.error(`[PAI] Claude Code version: ${version}`);
console.error(`[PAI] ${binary === 'gemini' ? 'Gemini CLI' : 'Claude Code'} version: ${version}`);
}
} catch {
// Silently ignore - version check is optional
Expand Down
30 changes: 30 additions & 0 deletions Packs/kai-prompting-skill/src/skills/Prompting/Standards.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,36 @@ When extended thinking is disabled:
- **Avoid:** "think", "think about", "think through"
- **Use instead:** "consider", "believe", "evaluate", "reflect", "assess"

---

# Gemini 2.x Behavioral Characteristics



## Context Window Utilization

- **Exploit the 2M+ window:** Gemini 2.x excels at processing massive documentation and entire codebases simultaneously.

- **Precision anchoring:** Use specific file/line references to guide attention within large contexts.



## Multimodal Reasoning

- **Visual Evidence:** Reference images, diagrams, and terminal screenshots directly.

- **Video Analysis:** Provide timestamps for specific events in screen recordings.



## Reasoning Models (Thinking)

- **Pro Thinking:** Use for complex architectural decisions and deep logic.

- **Flash:** Use for rapid implementation and high-speed execution.



---

# Key Principles
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -577,9 +577,10 @@ PAI packs are designed to be **platform-agnostic**:
| Platform | Status | Notes |
|----------|--------|-------|
| **Claude Code** | ✅ Full support | Native integration, all features work |
| **Gemini CLI** | ✅ Full support | Supported via `gemini-pai` adapter |
| **OpenCode** | ✅ Compatible | Skills/hooks may need adaptation |
| **Custom systems** | ✅ Compatible | Extract code, adapt to your structure |
| **Gemini Code / Codex** | 🔄 Testing | Should work with minor tweaks |
| **GPT-Codex** | 🔄 Testing | Should work with minor tweaks |
| **Manual use** | ✅ Always works | Packs are documentation + code |

The code itself is platform-independent (TypeScript, Python, Bash). Integration points (skills, hooks) may vary by platform.
Expand Down
38 changes: 38 additions & 0 deletions Tools/VERIFY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Verification Guide: PAI Tools

## Gemini Adapter (gemini-pai.ts)

The `gemini-pai` adapter is a wrapper for the Gemini CLI that integrates it with the PAI hook and history systems.

### Quick Verification

Run these commands to verify the adapter:

```bash
# 1. Verify the adapter exists and is executable
ls -la $PAI_DIR/tools/gemini-pai.ts
# OR if you are in the repository:
ls -la Tools/gemini-pai.ts

# 2. Test the adapter's help (should pass through to gemini --help)
alias gemini-pai="bun $PAI_DIR/tools/gemini-pai.ts"
gemini-pai --help

# 3. Test context injection (Dry Run)
PAI_DEBUG=true gemini-pai --version
```

### Functional Verification

1. **Session Initialization**:
- Run `gemini-pai`
- Check if `$PAI_DIR/.current-session` was updated.

2. **Context Injection**:
- Run `gemini-pai` (interactive mode)
- Ask: "Who are you and what is your operating environment?"
- It should respond with the name and environment defined in your `CORE/SKILL.md` (e.g., "[AI_NAME]", "[USER_NAME]'s AI assistant", "built on Claude Code / Gemini CLI").

3. **History Capture**:
- Complete a session in `gemini-pai`.
- Check `$PAI_DIR/history/sessions/` for a new markdown file.
204 changes: 204 additions & 0 deletions Tools/gemini-pai.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
#!/usr/bin/env bun
/**
* PAI Gemini Adapter
*
* A wrapper for the Gemini CLI that integrates it with the
* Personal AI Infrastructure (PAI) hook and history systems.
*/

import { join } from "path";
import { homedir } from "os";
import { existsSync, readFileSync } from "fs";

export function getPAIDir() {
if (process.env.PAI_DIR) return process.env.PAI_DIR;

// Self-awareness: If we are in <PAI_DIR>/tools/gemini-pai.ts
const possiblePaiDir = join(import.meta.dir, "..");
if (existsSync(join(possiblePaiDir, "skills", "CORE", "SKILL.md"))) {
return possiblePaiDir;
}

// Fallback to standard location
return join(homedir(), ".config", 'pai');
}

export function loadEnv(paiDir: string) {
const envPath = join(paiDir, ".env");
if (existsSync(envPath)) {
const envContent = readFileSync(envPath, "utf-8");
for (const line of envContent.split("\n")) {
const trimmed = line.trim();
if (trimmed && !trimmed.startsWith("#") && trimmed.includes("=")) {
const equalsIndex = trimmed.indexOf("=");
const key = trimmed.slice(0, equalsIndex).trim();
const value = trimmed.slice(equalsIndex + 1).trim();
process.env[key] = value;
}
}
}
}

export function getPAIContext(paiDir: string): string {
try {
const coreSkillPath = join(paiDir, "skills", "CORE", "SKILL.md");
if (existsSync(coreSkillPath)) {
const coreSkill = readFileSync(coreSkillPath, "utf-8");
const indexPath = join(paiDir, "skills", "skill-index.json");
let skillsSummary = "";
if (existsSync(indexPath)) {
const index = JSON.parse(readFileSync(indexPath, "utf-8"));
skillsSummary = Object.values(index.skills)
.filter((s: any) => s.name !== "CORE")
.map((s: any) => `- ${s.name}: ${s.fullDescription}`)
.join("\n");
}

const cleanCore = coreSkill.replace(/\0/g, "").trim();
const cleanSkills = skillsSummary.replace(/\0/g, "").trim();

return `[ PAI SYSTEM INITIALIZATION ]
${cleanCore}

AVAILABLE SKILLS INDEX:
${cleanSkills}

[ STATUS: Infrastructure Loaded ]
[ IDENTITY: ${process.env.DA || 'PAI'} ]
[ SOURCE: ${process.env.PAI_SOURCE_APP || 'Gemini'} ]

[ END SYSTEM CONTEXT ]`;
}
} catch (e) {}
return "";
}

export async function runHook(paiDir: string, name: string, payload: any, debug: boolean = false) {
const hookPath = join(paiDir, "hooks", name);
if (existsSync(hookPath)) {
try {
const proc = Bun.spawn(["bun", hookPath], {
stdin: "pipe",
stdout: "ignore",
stderr: "inherit",
env: process.env
});
proc.stdin.write(JSON.stringify(payload));
proc.stdin.end();
await proc.exited;
} catch (e) {}
}
}

async function main() {
const PAI_DIR = getPAIDir();
loadEnv(PAI_DIR);

const SESSION_ID = crypto.randomUUID();
const CWD = process.cwd();
process.env.PAI_SOURCE_APP = "GeminiCLI";
const DEBUG = process.env.PAI_DEBUG === "true";

await runHook(PAI_DIR, "initialize-session.ts", { session_id: SESSION_ID, cwd: CWD }, DEBUG);

try {
const userArgs = process.argv.slice(2);
const finalArgs: string[] = ["gemini"];

const geminiCommands = ["mcp", "extensions", "extension"];
const isCommand = userArgs.length > 0 && geminiCommands.includes(userArgs[0]);
const isHelp = userArgs.includes("-h") || userArgs.includes("--help") || userArgs.includes("-v") || userArgs.includes("--version");

const shouldInject = !isCommand && !isHelp;

if (shouldInject) {
const context = getPAIContext(PAI_DIR);
let userPrompt = "";
let promptFlagIndex = -1;
const promptFlags = ["-i", "--prompt-interactive", "-p", "--prompt"];

// Extract prompt and check for explicit interactive flags
let explicitInteractive = false;

for (let i = 0; i < userArgs.length; i++) {
if (userArgs[i] === "-i" || userArgs[i] === "--prompt-interactive") {
explicitInteractive = true;
}

if (promptFlags.includes(userArgs[i])) {
promptFlagIndex = i;
userPrompt = userArgs[i + 1] || "";
// If we found the prompt via flag, we stop looking
break;
}
}

// If no prompt found via flags, check positional args
if (promptFlagIndex === -1 && userArgs.length > 0) {
// Find first non-flag arg
for (let i = 0; i < userArgs.length; i++) {
if (!userArgs[i].startsWith("-")) {
userPrompt = userArgs[i];
promptFlagIndex = i;
break;
}
}
}

// Default prompt if none provided (implies interactive startup)
const isStartup = !userPrompt;
const finalUserPrompt = userPrompt || "PAI Active. Initialization complete. Please wait for my instruction.";
const combinedPrompt = context ? `${context}\n\nUSER INSTRUCTION:\n${finalUserPrompt}` : finalUserPrompt;

// Determine mode: Interactive if explicit flag OR it's a startup (no prompt)
const isInteractive = explicitInteractive || isStartup;

// Reconstruct Args
if (isInteractive) {
finalArgs.push("-i");
}

// Add the combined prompt (positional)
finalArgs.push(combinedPrompt);

// Add back all other args, skipping the original prompt and interactive flags that we handled/replaced
for (let i = 0; i < userArgs.length; i++) {
const isPromptFlag = promptFlagIndex !== -1 && i === promptFlagIndex;
const isPromptValue = promptFlagIndex !== -1 && i === promptFlagIndex + 1 && promptFlags.includes(userArgs[promptFlagIndex]); // Value after flag
const isPositionalPrompt = promptFlagIndex !== -1 && i === promptFlagIndex && !promptFlags.includes(userArgs[promptFlagIndex]); // Positional value
const isInteractiveFlag = userArgs[i] === "-i" || userArgs[i] === "--prompt-interactive";

if (isPromptFlag || isPromptValue || isPositionalPrompt || isInteractiveFlag) {
continue;
}
finalArgs.push(userArgs[i]);
}
} else {
finalArgs.push(...userArgs);
}

if (shouldInject && process.env.GEMINI_MODEL && !finalArgs.includes("-m") && !finalArgs.includes("--model")) {
finalArgs.push("--model", process.env.GEMINI_MODEL);
}

const proc = Bun.spawn(finalArgs, {
stdin: "inherit",
stdout: "inherit",
stderr: "inherit",
env: { ...process.env, PAI_SESSION_ID: SESSION_ID }
});

const exitCode = await proc.exited;

if (shouldInject) {
await runHook(PAI_DIR, "stop-hook.ts", { stop_hook_active: true, session_id: SESSION_ID, response: "Gemini session completed." }, DEBUG);
}

process.exit(exitCode);
} catch (e) {
const proc = Bun.spawn(["gemini", ...process.argv.slice(2)], { stdin: "inherit", stdout: "inherit", stderr: "inherit" });
process.exit(await proc.exited);
}
}

if (import.meta.main) main();
Loading