+
+
+ ✦ opengap
+
+
+ An open standard for AI agent definitions.
+
+
+
+
+
+
-
+ )}
- gitagent is an open standard. MIT License.
+ {variant === "gitagent" ? "gitagent is open source. MIT License." : "opengap is an open standard. MIT License."}
Open Standard created by Shreyas Kapale
diff --git a/src/components/HeroSection.tsx b/src/components/HeroSection.tsx
index bb6262e..d04cb05 100644
--- a/src/components/HeroSection.tsx
+++ b/src/components/HeroSection.tsx
@@ -39,16 +39,6 @@ const tree: TreeNode[] = [
icon: ,
color: "text-muted-foreground",
},
- {
- name: "INSTRUCTIONS.md",
- icon: ,
- color: "text-muted-foreground",
- },
- {
- name: "scheduler.yml",
- icon: ,
- color: "text-muted-foreground",
- },
{
name: "skills/",
icon: ,
@@ -153,9 +143,9 @@ const adapters = [
];
const buildCmd = (flag: string) =>
- `npx @open-gitagent/gitagent@latest run -r https://github.com/shreyas-lyzr/architect -a ${flag}${flag !== "claude" ? ' -p "hello"' : ''}`;
+ `npx @open-gitagent/opengap@latest run -r https://github.com/shreyas-lyzr/architect -a ${flag}${flag !== "claude" ? ' -p "hello"' : ''}`;
-export function HeroSection() {
+export function HeroSection({ noBackground = false }: { noBackground?: boolean }) {
const [copied, setCopied] = useState(false);
const [selectedAdapter, setSelectedAdapter] = useState(adapters[0]);
const [dropdownOpen, setDropdownOpen] = useState(false);
@@ -170,8 +160,40 @@ export function HeroSection() {
};
return (
-
-
+
+ {!noBackground && (
+ <>
+ {/* Vibrant ambient orbs */}
+
+
+
+
+
+
+ {/* Bottom fade into light page */}
+
+ >
+ )}
- No single agent should control a critical process end-to-end. Define roles (maker, checker, executor, auditor) in agent.yaml + DUTIES.md with conflict matrices and handoff rules — gitagent validate catches violations before deployment.
+ No single agent should control a critical process end-to-end. Define roles (maker, checker, executor, auditor) in agent.yaml + DUTIES.md with conflict matrices and handoff rules — opengap validate catches violations before deployment.
-a claude # Run with Claude Code",
+ "$ npm install -g @open-opengap/opengap # Install the CLI",
+ "$ opengap init --template standard # Scaffold an agent",
+ "$ opengap validate # Check it's valid",
+ "$ opengap run -d ./my-agent # Run with Claude Code",
+ "$ opengap run -a github -p \"Review\" # Run with GitHub Models",
+ "$ opengap export --format openai # Export for OpenAI SDK",
+ "$ opengap run -r -a claude # Run with Claude Code",
];
export function QuickStartSection() {
+ const [copied, setCopied] = useState(false);
+
+ const handleCopy = () => {
+ navigator.clipboard.writeText(steps.join('\n'));
+ setCopied(true);
+ setTimeout(() => setCopied(false), 2000);
+ };
+
return (
@@ -37,6 +47,13 @@ export function QuickStartSection() {
terminal
+
+ {copied ? : }
+
diff --git a/src/components/SkillsFlowSection.tsx b/src/components/SkillsFlowSection.tsx
index 4f7094c..d776fab 100644
--- a/src/components/SkillsFlowSection.tsx
+++ b/src/components/SkillsFlowSection.tsx
@@ -1,5 +1,6 @@
+import { useState } from "react";
import { motion } from "framer-motion";
-import { GitFork, Zap, MessageSquare, Wrench, ArrowDown } from "lucide-react";
+import { GitFork, Zap, MessageSquare, Wrench, ArrowDown, Copy, Check } from "lucide-react";
const features = [
{
@@ -71,6 +72,14 @@ error_handling:
channel: "#eng-reviews"`;
export function SkillsFlowSection() {
+ const [copied, setCopied] = useState(false);
+
+ const handleCopy = () => {
+ navigator.clipboard.writeText(yamlCode);
+ setCopied(true);
+ setTimeout(() => setCopied(false), 2000);
+ };
+
return (
@@ -100,6 +109,13 @@ export function SkillsFlowSection() {
workflow
+
+ {copied ? : }
+
{yamlCode}
diff --git a/src/components/SkillsSection.tsx b/src/components/SkillsSection.tsx
index 78f78c6..8c57940 100644
--- a/src/components/SkillsSection.tsx
+++ b/src/components/SkillsSection.tsx
@@ -1,5 +1,6 @@
+import { useState } from "react";
import { motion } from "framer-motion";
-import { Zap, Search, Download, List, Folder } from "lucide-react";
+import { Zap, Search, Download, List, Folder, Copy, Check } from "lucide-react";
const discoveryPaths = [
{ path: "/skills/", source: "Agent-local", priority: 1 },
@@ -10,13 +11,47 @@ const discoveryPaths = [
];
const skillCommands = [
- { icon: Search, cmd: "gitagent skills search \"code review\"", desc: "Search SkillsMP or GitHub" },
- { icon: Download, cmd: "gitagent skills install code-review --global", desc: "Install to global or local" },
- { icon: List, cmd: "gitagent skills list", desc: "List discovered skills" },
- { icon: Zap, cmd: "gitagent skills info code-review", desc: "Inspect skill metadata" },
+ { icon: Search, cmd: "opengap skills search \"code review\"", desc: "Search SkillsMP or GitHub" },
+ { icon: Download, cmd: "opengap skills install code-review --global", desc: "Install to global or local" },
+ { icon: List, cmd: "opengap skills list", desc: "List discovered skills" },
+ { icon: Zap, cmd: "opengap skills info code-review", desc: "Inspect skill metadata" },
];
+const skillMdContent = `---
+name: code-review
+description: Thorough code reviews
+license: MIT
+compatibility: ">=0.4.0"
+allowed-tools: Read Edit Grep Glob Bash
+metadata:
+ author: "Jane Doe"
+ version: "1.0.0"
+ category: "developer-tools"
+---
+
+# Instructions
+
+Review the code for:
+1. Security vulnerabilities
+2. Performance issues
+3. Code style consistency`;
+
export function SkillsSection() {
+ const [copiedSkill, setCopiedSkill] = useState(false);
+ const [copiedCmd, setCopiedCmd] = useState(null);
+
+ const handleSkillCopy = () => {
+ navigator.clipboard.writeText(skillMdContent);
+ setCopiedSkill(true);
+ setTimeout(() => setCopiedSkill(false), 2000);
+ };
+
+ const handleCmdCopy = (cmd: string) => {
+ navigator.clipboard.writeText(cmd);
+ setCopiedCmd(cmd);
+ setTimeout(() => setCopiedCmd(null), 2000);
+ };
+
return (
@@ -43,25 +78,21 @@ export function SkillsSection() {
viewport={{ once: true }}
>
SKILL.md Format
-
-
{`---
-name: code-review
-description: Thorough code reviews
-license: MIT
-compatibility: ">=0.1.0"
-allowed-tools: Read Edit Grep Glob Bash
-metadata:
- author: "Jane Doe"
- version: "1.0.0"
- category: "developer-tools"
----
-
-# Instructions
-
-Review the code for:
-1. Security vulnerabilities
-2. Performance issues
-3. Code style consistency`}
+
+
+
+
+
+ SKILL.md
+
+ {copiedSkill ? : }
+
+
+
{skillMdContent}
Discovery Priority
@@ -97,6 +128,13 @@ Review the code for:
{s.desc}
+ handleCmdCopy(s.cmd)}
+ className="ml-auto text-muted-foreground/30 hover:text-foreground transition-colors shrink-0"
+ aria-label="Copy command"
+ >
+ {copiedCmd === s.cmd ? : }
+
$ {s.cmd}
diff --git a/src/components/WhySection.tsx b/src/components/WhySection.tsx
index 99fbc97..02d9191 100644
--- a/src/components/WhySection.tsx
+++ b/src/components/WhySection.tsx
@@ -10,7 +10,7 @@ const features: { label: string; desc: string; icon: LucideIcon }[] = [
},
{
label: "Framework-Agnostic",
- desc: "Works with Claude Code, OpenAI, CrewAI, LangChain, and more. Define once, export anywhere.",
+ desc: "Works with Claude Code, OpenAI, CrewAI, Gemini, and more. Define once, export anywhere.",
icon: Blocks,
},
{
@@ -35,7 +35,7 @@ export function WhySection() {
viewport={{ once: true }}
className="mb-12"
>
-
Why GitAgent: The Git-Native AI Agent Standard
+
Why OpenGAP: The Git-Native AI Agent Standard
Everything your agent needs, defined in files you already know how to manage.
diff --git a/src/components/gitAgent/CodeBlock.tsx b/src/components/gitAgent/CodeBlock.tsx
new file mode 100644
index 0000000..68005b7
--- /dev/null
+++ b/src/components/gitAgent/CodeBlock.tsx
@@ -0,0 +1,60 @@
+import { useState } from "react";
+import { Copy, Check } from "lucide-react";
+import { track } from "@/lib/analytics";
+
+interface CodeBlockProps {
+ code: string;
+ filename?: string;
+ trackEvent?: string;
+ codeClassName?: string;
+ className?: string;
+}
+
+export function CodeBlock({
+ code,
+ filename,
+ trackEvent,
+ codeClassName,
+ className,
+}: CodeBlockProps) {
+ const [copied, setCopied] = useState(false);
+
+ const handleCopy = () => {
+ navigator.clipboard.writeText(code);
+ setCopied(true);
+ setTimeout(() => setCopied(false), 2000);
+ if (trackEvent) track(trackEvent);
+ };
+
+ return (
+
+
+
+
+
+ {filename && (
+ {filename}
+ )}
+
+ {copied ? (
+
+ ) : (
+
+ )}
+
+
+
+ {code}
+
+
+ );
+}
diff --git a/src/components/gitAgent/GitAgentArchitecture.tsx b/src/components/gitAgent/GitAgentArchitecture.tsx
new file mode 100644
index 0000000..10f9fc1
--- /dev/null
+++ b/src/components/gitAgent/GitAgentArchitecture.tsx
@@ -0,0 +1,262 @@
+import { useState } from "react";
+import { motion } from "framer-motion";
+import { CodeBlock } from "@/components/gitAgent/CodeBlock";
+
+const directoryTree = `my-agent/
+├── agent.yaml # Model, tools, runtime config
+├── SOUL.md # Agent identity & personality
+├── RULES.md # Behavioral rules & constraints
+├── DUTIES.md # Role-specific responsibilities
+├── memory/
+│ └── MEMORY.md # Git-committed agent memory
+├── tools/
+│ └── *.yaml # Declarative tool definitions
+├── skills/
+│ └──
/
+│ ├── SKILL.md # Skill instructions (YAML frontmatter)
+│ └── scripts/ # Skill scripts
+├── workflows/
+│ └── *.yaml|*.md # Multi-step workflow definitions
+├── agents/
+│ └── / # Sub-agent definitions
+├── plugins/
+│ └── / # Local plugins (plugin.yaml + tools/hooks/skills)
+├── hooks/
+│ └── hooks.yaml # Lifecycle hook scripts
+├── knowledge/
+│ └── index.yaml # Knowledge base entries
+├── config/
+│ ├── default.yaml # Default environment config
+│ └── .yaml # Environment overrides
+├── examples/
+│ └── *.md # Few-shot examples
+└── compliance/
+ └── *.yaml # Compliance & audit config`;
+
+const identityFiles = [
+ {
+ name: "SOUL.md",
+ desc: "Agent personality, identity, core values",
+ },
+ {
+ name: "RULES.md",
+ desc: "Behavioral constraints and rules",
+ },
+ {
+ name: "DUTIES.md",
+ desc: "Job responsibilities and tasks",
+ },
+ {
+ name: "AGENTS.md",
+ desc: "Sub-agent relationships and delegation rules",
+ },
+];
+
+const yamlTabs = [
+ {
+ label: "Minimal",
+ code: `spec_version: "0.4.0"
+name: my-agent
+version: 1.0.0
+description: An agent that does things
+
+model:
+ preferred: "anthropic:claude-sonnet-4-6"
+ fallback: ["openai:gpt-4o"]
+ constraints:
+ temperature: 0.7
+ max_tokens: 4096
+
+tools: [cli, read, write, memory]
+
+runtime:
+ max_turns: 50
+ timeout: 120`,
+ },
+ {
+ label: "Full (with compliance)",
+ code: `spec_version: "0.4.0"
+name: my-agent
+version: 1.0.0
+description: A description of what this agent does
+
+model:
+ preferred: "anthropic:claude-sonnet-4-6"
+ fallback:
+ - "openai:gpt-4o"
+ - "google:gemini-2.0-flash-001"
+ constraints:
+ temperature: 0.7
+ max_tokens: 4096
+
+tools:
+ - cli
+ - read
+ - write
+ - memory
+ - capture_photo
+ - task_tracker
+ - skill_learner
+
+skills:
+ - code-review
+ - deployment
+
+runtime:
+ max_turns: 50
+ timeout: 300
+
+extends: https://github.com/user/parent-agent.git
+
+dependencies:
+ - name: shared-skills
+ source: https://github.com/team/shared-skills
+ version: main
+ mount: deps/shared
+
+agents:
+ researcher:
+ model: "anthropic:claude-haiku-4-5-20251001"
+ tools: [read, cli]
+
+delegation:
+ mode: auto
+
+plugins:
+ my-plugin:
+ enabled: true
+ config:
+ api_key: "\${MY_PLUGIN_KEY}"
+
+compliance:
+ risk_level: high
+ human_in_the_loop: true
+ data_classification: "confidential"
+ regulatory_frameworks: [SOX, GLBA]
+ recordkeeping:
+ audit_logging: true
+ retention_days: 2555
+ review:
+ required_approvers: 2
+ auto_review: false
+
+serve:
+ port: 8080
+ allowed_tools: [lookup_account, get_policy]
+ constraints:
+ temperature: 0
+ max_tokens: 4000`,
+ },
+];
+
+export function GitAgentArchitecture() {
+ const [activeTab, setActiveTab] = useState(0);
+
+ return (
+
+
+ {/* Section heading */}
+
+
+ Agent Directory Structure
+
+
+ Every agent is a Git repository. These files define its identity, behavior, and capabilities.
+
+
+
+ {/* A. Directory Tree */}
+
+
+ Directory Layout
+
+
+
+
+ {/* B. Identity Files — 2×2 grid */}
+
+
+ Identity Files
+
+
+ {identityFiles.map((file, i) => (
+
+
+
+ {file.name}
+
+
+
+ {file.desc}
+
+
+ ))}
+
+
+
+ {/* C. Tabbed agent.yaml */}
+
+
+ agent.yaml Schema
+
+
+ {/* Tabs */}
+
+ {yamlTabs.map((tab, i) => (
+ setActiveTab(i)}
+ className={`px-3 sm:px-4 py-2 sm:py-2.5 text-xs font-body transition-colors relative ${
+ activeTab === i
+ ? "text-foreground"
+ : "text-muted-foreground hover:text-foreground"
+ }`}
+ >
+ {tab.label}
+ {activeTab === i && (
+
+ )}
+
+ ))}
+
+
+ {/* Code block */}
+
+
+
+
+ );
+}
diff --git a/src/components/gitAgent/GitAgentArchitectureSection.tsx b/src/components/gitAgent/GitAgentArchitectureSection.tsx
new file mode 100644
index 0000000..045cb28
--- /dev/null
+++ b/src/components/gitAgent/GitAgentArchitectureSection.tsx
@@ -0,0 +1,202 @@
+import { useState } from "react";
+import { motion } from "framer-motion";
+
+const dirTree = `~/assistant/ # Agent root (git repo)
+├── agent.yaml # Agent manifest
+├── SOUL.md # Agent identity
+├── RULES.md # Behavior rules (optional)
+├── DUTIES.md # Responsibilities (optional)
+├── .env # API keys (gitignored)
+├── workspace/ # Output directory
+├── memory/
+│ ├── MEMORY.md # Primary memory
+│ ├── mood.md # Mood tracking
+│ ├── photos/ # Captured moments
+│ ├── journal/ # Session reflections
+│ └── archive/ # Archived entries
+├── skills/
+│ └── skill-name/
+│ └── SKILL.md
+├── workflows/ # SkillFlows + .md workflows
+├── schedules/ # Cron jobs
+├── hooks/
+│ ├── hooks.yaml
+│ └── validate.sh # example name — any .sh filename works
+├── tools/ # Custom declarative tools
+├── plugins/ # Installed plugins
+├── config/
+│ ├── default.yaml
+│ └── production.yaml
+├── knowledge/ # Knowledge base
+├── compliance/ # Compliance config
+└── .gitagent/ # Internal state (gitignored)
+ ├── state.json
+ ├── audit.jsonl
+ └── learning/`;
+
+const tabs = [
+ {
+ label: "agent.yaml",
+ code: `spec_version: "0.4.0"
+name: my-agent
+version: 1.0.0
+description: An agent that does things
+
+model:
+ preferred: "anthropic:claude-sonnet-4-6"
+ fallback: ["openai:gpt-4o", "google:gemini-2.0-flash-001"]
+ constraints:
+ temperature: 0.7
+ max_tokens: 4096
+
+tools: [cli, read, write, memory]
+
+runtime:
+ max_turns: 50
+ timeout: 300
+
+# Optional
+extends: "https://github.com/org/base-agent.git"
+skills: [code-review, deploy]
+delegation:
+ mode: auto
+compliance:
+ risk_level: high
+ human_in_the_loop: true
+ recordkeeping:
+ audit_logging: true`,
+ },
+ {
+ label: "SOUL.md",
+ code: `# Soul
+
+## Core Identity
+I am a focused, reliable autonomous coding agent.
+I analyze, implement, test, and document — with
+minimal interruption to the developer.
+
+## Communication Style
+Direct and concise. I report what I did and why,
+not a running commentary on my process.
+
+## Values & Principles
+- Correctness over speed
+- Every change is reviewable
+- No silent mutations to files I wasn't asked to touch
+- Ask before deleting or overwriting
+
+## Domain Expertise
+- Software architecture and code quality
+- Security review (OWASP Top 10)
+- Performance optimization
+- Git workflows and code review`,
+ },
+ {
+ label: "RULES.md",
+ code: `# Rules
+
+1. **Read before modifying** — always read a file
+ before editing it.
+
+2. **No destructive commands** — never run
+ \`rm -rf\`, \`git reset --hard\`, or \`DROP TABLE\`
+ without explicit confirmation.
+
+3. **No secrets in memory** — never write API keys,
+ passwords, or tokens to MEMORY.md.
+
+4. **Stay in scope** — only touch files that are
+ directly relevant to the current task.
+
+5. **Report errors honestly** — if something fails,
+ report the exact error; do not fabricate results.`,
+ },
+];
+
+export function GitAgentArchitectureSection() {
+ const [active, setActive] = useState(0);
+
+ return (
+
+
+
+
+ 02 — Architecture
+
+
+ Architecture
+
+
+ Everything your agent needs, defined in plain files you already know how to manage.
+
+
+
+
+ {/* Directory tree */}
+
+
+ Directory Structure
+
+
+
+
+
+
+ ~/assistant/
+
+
+ {dirTree}
+
+
+
+
+ {/* Tabbed config files */}
+
+
+ Core Files
+
+ {/* Tabs */}
+
+ {tabs.map((t, i) => (
+ setActive(i)}
+ className={`px-3 py-2 text-xs font-body transition-colors relative ${
+ active === i ? "text-foreground" : "text-muted-foreground hover:text-foreground"
+ }`}
+ >
+ {t.label}
+ {active === i && (
+
+ )}
+
+ ))}
+
+
+
+ {tabs[active].code}
+
+
+
+
+
+
+ );
+}
diff --git a/src/components/gitAgent/GitAgentCLI.tsx b/src/components/gitAgent/GitAgentCLI.tsx
new file mode 100644
index 0000000..6c1ac38
--- /dev/null
+++ b/src/components/gitAgent/GitAgentCLI.tsx
@@ -0,0 +1,159 @@
+import { motion } from "framer-motion";
+import { CodeBlock } from "@/components/gitAgent/CodeBlock";
+
+const cliFlags = [
+ { flag: "--dir ", short: "-d", desc: "Agent directory", default: "current working directory" },
+ { flag: "--model ", short: "-m", desc: "Override model from agent.yaml", default: "from agent.yaml" },
+ { flag: "--prompt \"text\"", short: "-p", desc: "Run a single prompt (non-interactive)", default: "—" },
+ { flag: "--env ", short: "-e", desc: "Load config/.yaml environment overrides", default: "default" },
+ { flag: "--voice", short: "-v", desc: "Start Web UI + voice server at localhost:3333", default: "—" },
+ { flag: "--sandbox", short: "-s", desc: "Run agent inside an E2B cloud VM", default: "false" },
+ { flag: "--sandbox-repo ", short: "—", desc: "Clone a repo into the sandbox", default: "—" },
+ { flag: "--sandbox-token ", short: "—", desc: "Git token for cloning (falls back to GITHUB_TOKEN / GIT_TOKEN)", default: "—" },
+ { flag: "--repo ", short: "—", desc: "Work on a remote git repo locally", default: "—" },
+ { flag: "--pat ", short: "—", desc: "Personal access token for --repo", default: "—" },
+ { flag: "--session ", short: "—", desc: "Session branch name for --repo mode", default: "auto-generated" },
+];
+
+const replCommands = [
+ { cmd: "/quit or /exit", desc: "Exit the session" },
+ { cmd: "/memory", desc: "View the current memory file" },
+ { cmd: "/skills", desc: "List all installed skills" },
+ { cmd: "/learned", desc: "Show learned skills with confidence, usage, and success stats" },
+ { cmd: "/tasks", desc: "Show currently active tasks" },
+ { cmd: "/plugins", desc: "List loaded plugins and what they provide" },
+ { cmd: "/skill:", desc: "Execute a specific skill (e.g. /skill:deploy)" },
+];
+
+const pluginCliCode = `gitagent plugin install https://github.com/user/plugin-repo
+gitagent plugin install ./local/path --name my-plugin --force
+gitagent plugin list --dir ~/assistant
+gitagent plugin enable my-plugin --dir ~/assistant
+gitagent plugin disable my-plugin --dir ~/assistant
+gitagent plugin remove my-plugin --dir ~/assistant
+gitagent plugin init my-plugin --dir ~/assistant`;
+
+export function GitAgentCLI() {
+ return (
+
+
+
+ CLI
+
+ The primary way to run GitAgent. Starts an interactive REPL in your terminal.
+
+
+
+ {/* Basic usage */}
+
+
+ Basic Usage
+
+
+
+
+
+ {/* Left: CLI Flags */}
+
+
+ All Flags
+
+
+ {cliFlags.map((row, i) => (
+
+
+
+
+ {row.flag}
+
+ {row.short !== "—" && (
+
+ {row.short}
+
+ )}
+
+
+
+ {row.desc}
+
+
+ default: {row.default}
+
+
+
+
+ ))}
+
+
+
+ {/* Right: REPL Commands + Plugin CLI */}
+
+
+
+ REPL Commands
+
+
+ {replCommands.map((row, i) => (
+
+
+
+ {row.cmd}
+
+
—
+
+ {row.desc}
+
+
+
+ ))}
+
+
+
+
+
+ Plugin CLI
+
+
+
+
+
+
+
+ );
+}
diff --git a/src/components/gitAgent/GitAgentCompliance.tsx b/src/components/gitAgent/GitAgentCompliance.tsx
new file mode 100644
index 0000000..600ea21
--- /dev/null
+++ b/src/components/gitAgent/GitAgentCompliance.tsx
@@ -0,0 +1,191 @@
+import { motion } from "framer-motion";
+import { CodeBlock } from "@/components/gitAgent/CodeBlock";
+
+const riskLevels = [
+ { level: "low", label: "Low", desc: "Minimal — standard logging", color: "text-green-600", bg: "bg-green-500/10" },
+ { level: "medium", label: "Medium", desc: "Audit logging recommended", color: "text-yellow-600", bg: "bg-yellow-500/10" },
+ {
+ level: "high",
+ label: "High",
+ desc: "HITL required, audit logging, compliance artifacts",
+ color: "text-orange-600",
+ bg: "bg-orange-500/10",
+ },
+ {
+ level: "critical",
+ label: "Critical",
+ desc: "Kill switch required, immutable logs, quarterly validation — prints a compliance error at startup if audit_logging missing (execution still continues)",
+ color: "text-destructive",
+ bg: "bg-destructive/10",
+ },
+];
+
+const complianceYaml = `compliance:
+ risk_level: critical # low | medium | high | critical
+ human_in_the_loop: true
+ data_classification: "PCI-DSS"
+ regulatory_frameworks: [SOX, GLBA, OCC]
+ recordkeeping:
+ audit_logging: true
+ retention_days: 2555 # 7 years for banking
+ review:
+ required_approvers: 2
+ auto_review: false`;
+
+const validationRules = [
+ {
+ rule: "high_risk_hitl",
+ condition: "High/critical risk without human_in_the_loop",
+ severity: "warning",
+ },
+ {
+ rule: "critical_audit",
+ condition: "Critical risk without audit_logging",
+ severity: "error",
+ },
+ {
+ rule: "regulatory_recordkeeping",
+ condition: "Regulatory frameworks without recordkeeping",
+ severity: "warning",
+ },
+ {
+ rule: "high_risk_review",
+ condition: "High/critical risk without review config",
+ severity: "warning",
+ },
+ {
+ rule: "audit_retention",
+ condition: "Audit logging without retention_days",
+ severity: "warning",
+ },
+];
+
+const auditLogJson = `{"timestamp":"2026-01-15T14:23:45Z","session_id":"uuid","event":"session_start"}
+{"timestamp":"2026-01-15T14:23:46Z","session_id":"uuid","event":"tool_use","tool":"cli","args":{"command":"ls"}}
+{"timestamp":"2026-01-15T14:23:47Z","session_id":"uuid","event":"tool_result","tool":"cli","result":"file.txt"}
+{"timestamp":"2026-01-15T14:23:48Z","session_id":"uuid","event":"response"}
+{"timestamp":"2026-01-15T14:23:49Z","session_id":"uuid","event":"session_end"}`;
+
+export function GitAgentCompliance() {
+ return (
+
+
+
+ Compliance
+
+ Risk levels, validation rules, compliance configuration, and immutable audit logging.
+
+
+
+
+ {/* A. Risk Levels */}
+
+
+ Risk Levels
+
+
+ {riskLevels.map((r, i) => (
+
+
+
+ {r.label}
+
+
{r.desc}
+
+
+ ))}
+
+
+
+ {/* B. Compliance config */}
+
+
+ Compliance Config (agent.yaml)
+
+
+
+
+
+ {/* C. Validation Rules */}
+
+
+ Validation Rules
+
+
+
+ {validationRules.map((r, i) => (
+
+
+
+ {r.rule}
+
+ {r.condition}
+
+ {r.severity}
+
+
+
+ ))}
+
+
+
+
+ {/* D. Audit Log format */}
+
+
+ Audit Log Format
+
+
+
+ Logged to{" "}
+ .gitagent/audit.jsonl when{" "}
+ audit_logging: true
+
+
+
+
+ );
+}
diff --git a/src/components/gitAgent/GitAgentEnvVars.tsx b/src/components/gitAgent/GitAgentEnvVars.tsx
new file mode 100644
index 0000000..3031c23
--- /dev/null
+++ b/src/components/gitAgent/GitAgentEnvVars.tsx
@@ -0,0 +1,104 @@
+import { useState } from "react";
+import { motion } from "framer-motion";
+
+const envVars = [
+ { name: "ANTHROPIC_API_KEY", default: "—", desc: "API key for Anthropic Claude models" },
+ { name: "OPENAI_API_KEY", default: "—", desc: "API key for OpenAI models (also used for Lyzr)" },
+ { name: "GOOGLE_API_KEY", default: "—", desc: "API key for the google: text model provider" },
+ { name: "GEMINI_API_KEY", default: "—", desc: "API key for Gemini Live voice mode" },
+ { name: "GROQ_API_KEY", default: "—", desc: "API key for Groq" },
+ { name: "XAI_API_KEY", default: "—", desc: "API key for xAI Grok models" },
+ { name: "MISTRAL_API_KEY", default: "—", desc: "API key for Mistral models" },
+ { name: "OPENROUTER_API_KEY", default: "—", desc: "API key for OpenRouter (multi-provider proxy)" },
+ { name: "CEREBRAS_API_KEY", default: "—", desc: "API key for Cerebras" },
+ { name: "DEEPSEEK_API_KEY", default: "—", desc: "API key for DeepSeek" },
+ { name: "LYZR_API_KEY", default: "—", desc: "Lyzr AI Studio API key" },
+ { name: "GITHUB_TOKEN", default: "—", desc: "GitHub PAT for --repo mode (also falls back to GIT_TOKEN)" },
+ { name: "GIT_TOKEN", default: "—", desc: "Alternative PAT fallback for --repo mode" },
+ { name: "E2B_API_KEY", default: "—", desc: "API token read by the E2B SDK when using --sandbox" },
+ { name: "COMPOSIO_API_KEY", default: "—", desc: "Composio integrations API key" },
+ { name: "TELEGRAM_BOT_TOKEN", default: "—", desc: "Telegram bot token from @BotFather" },
+ { name: "GITAGENT_MODEL_BASE_URL", default: "—", desc: "Custom OpenAI-compatible base URL" },
+ { name: "GITAGENT_PASSWORD", default: "—", desc: "Password for web UI authentication" },
+];
+
+export function GitAgentEnvVars() {
+ const [filter, setFilter] = useState("");
+
+ const filtered = envVars.filter(
+ (v) =>
+ v.name.toLowerCase().includes(filter.toLowerCase()) ||
+ v.desc.toLowerCase().includes(filter.toLowerCase())
+ );
+
+ return (
+
+
+
+ Environment Variables
+
+ All supported environment variables and their defaults.
+
+
+
+ {/* Search input */}
+
+ setFilter(e.target.value)}
+ className="border border-border rounded px-3 py-2 text-sm font-body w-full bg-background text-foreground placeholder:text-muted-foreground/50 outline-none focus:border-primary/50 transition-colors"
+ />
+
+
+ {/* Env var list */}
+
+ {filtered.length === 0 && (
+
+ No environment variables match your search.
+
+ )}
+ {filtered.map((v, i) => (
+
+
+
+ {v.name}
+
+
+ {v.default}
+
+
+ {v.desc}
+
+
+
+ ))}
+
+
+
+ );
+}
diff --git a/src/components/gitAgent/GitAgentFeaturesSection.tsx b/src/components/gitAgent/GitAgentFeaturesSection.tsx
new file mode 100644
index 0000000..52fa5ef
--- /dev/null
+++ b/src/components/gitAgent/GitAgentFeaturesSection.tsx
@@ -0,0 +1,96 @@
+import { motion } from "framer-motion";
+import { Mic, Monitor, Cpu, Brain, Zap, Puzzle, GitBranch, ShieldCheck, Activity } from "lucide-react";
+
+const features = [
+ {
+ icon: ShieldCheck,
+ title: "Compliance & Audit",
+ desc: "Built-in risk tiers, human-in-the-loop enforcement, and regulatory support for SOX, GLBA, SOC2, and GDPR. Your compliance team reviews the config like any code PR — no black-box policies.",
+ },
+ {
+ icon: GitBranch,
+ title: "SkillFlows",
+ desc: "Chain tasks into reliable, repeatable workflows in plain YAML. Approval gates pause execution and wait for sign-off via Telegram or WhatsApp — so humans stay in control of critical steps.",
+ },
+ {
+ icon: Brain,
+ title: "Git-Native Memory",
+ desc: "The agent remembers context across sessions — and every memory write is a git commit you can audit, diff, or revert. No opaque data stores, no vendor lock-in on your agent's history.",
+ },
+ {
+ icon: Zap,
+ title: "Skills & Auto-Learning",
+ desc: "Completed tasks are crystallized into reusable skills automatically. The agent builds its own capability library over time — every skill is version-controlled and inspectable.",
+ },
+ {
+ icon: Mic,
+ title: "Voice & Camera",
+ desc: "Real-time bidirectional voice via OpenAI Realtime API or Gemini Live. Camera input lets your agent see what you see — meet your team on voice, not just text.",
+ },
+ {
+ icon: Cpu,
+ title: "12+ LLM Providers",
+ desc: "Switch between Anthropic, OpenAI, Google, Groq, Mistral, and more by changing one line. Prevents model vendor lock-in — your agent definition stays yours regardless of who runs the models.",
+ },
+ {
+ icon: Monitor,
+ title: "Web UI",
+ desc: "Full browser interface at localhost:3333 with tabs for Chat, Skills, Integrations, Communication, SkillFlows, Scheduler, and Settings. No CLI required for day-to-day use.",
+ },
+ {
+ icon: Puzzle,
+ title: "Plugin System",
+ desc: "Extend with tools, hooks, skills, and memory layers via plugin.yaml. Install from git URLs or local paths — composable by design, auditable by default.",
+ },
+ {
+ icon: Activity,
+ title: "OpenTelemetry",
+ desc: "Built-in observability — spans, tool execution traces, and session cost in USD. Point it at your existing OTEL collector and it works; leave it unset for zero overhead.",
+ },
+];
+
+export function GitAgentFeaturesSection() {
+ return (
+
+
+
+
+ 03 — Features
+
+
+ Features
+
+
+ Production-ready out of the box — auditable for compliance, composable for engineering.
+
+
+
+
+ {features.map((f, i) => (
+
+
+
+ {f.title}
+
+
+ {f.desc}
+
+
+ ))}
+
+
+
+ );
+}
diff --git a/src/components/gitAgent/GitAgentHero.tsx b/src/components/gitAgent/GitAgentHero.tsx
new file mode 100644
index 0000000..f97b51e
--- /dev/null
+++ b/src/components/gitAgent/GitAgentHero.tsx
@@ -0,0 +1,49 @@
+import { motion } from "framer-motion";
+
+export function GitAgentHero() {
+ return (
+
+
+
+
+ Documentation
+
+
+ GitAgent
+
+
+ A universal git-native multimodal always-learning AI agent. Your agent IS a git repo.
+
+
+
+
+
+ );
+}
diff --git a/src/components/gitAgent/GitAgentHeroSection.tsx b/src/components/gitAgent/GitAgentHeroSection.tsx
new file mode 100644
index 0000000..0fbfb86
--- /dev/null
+++ b/src/components/gitAgent/GitAgentHeroSection.tsx
@@ -0,0 +1,248 @@
+import { useState } from "react";
+import { motion } from "framer-motion";
+import { Copy, Check, BookOpen, Github, ArrowRight, Folder, FileText, Brain, Settings, Zap, Wrench, Database, GitFork, ShieldCheck } from "lucide-react";
+import { track } from "@/lib/analytics";
+
+const INSTALL_CMD = `bash <(curl -fsSL "https://raw.githubusercontent.com/open-gitagent/gitagent/main/install.sh?$(date +%s)")`;
+
+type TreeItem = { name: string; indent: number; icon: React.ReactNode; tag?: string };
+
+const tree: TreeItem[] = [
+ { name: "~/assistant/", indent: 0, icon: },
+ { name: "agent.yaml", indent: 1, icon: , tag: "manifest" },
+ { name: "SOUL.md", indent: 1, icon: , tag: "identity" },
+ { name: "RULES.md", indent: 1, icon: },
+ { name: "memory/", indent: 1, icon: },
+ { name: "MEMORY.md", indent: 2, icon: },
+ { name: "skills/", indent: 1, icon: },
+ { name: "tools/", indent: 1, icon: },
+ { name: "hooks/", indent: 1, icon: },
+ { name: "workflows/", indent: 1, icon: },
+ { name: "compliance/", indent: 1, icon: },
+];
+
+export function GitAgentHeroSection() {
+ const [copied, setCopied] = useState(false);
+
+ const handleCopy = () => {
+ navigator.clipboard.writeText(INSTALL_CMD);
+ setCopied(true);
+ setTimeout(() => setCopied(false), 2000);
+ track("gitagent_install_copied");
+ };
+
+ return (
+
+
+
+
+
+ {/* Left */}
+
+ {/* OpenGAP badge */}
+
+
+ OpenGAP
+ —
+ compliant
+ ↗
+
+
+
+ Git Agent
+
+
+
+ A git-native agent harness — identity, memory, rules, and skills live as plain files in a repo.
+
+
+ Full audit trail, human-in-the-loop controls, and zero vendor lock-in. Your agent config is code — version-controlled, reviewable, and reversible.
+
+
+ {/* Meta badges */}
+
+ {[
+ { label: "node ≥ 20", dot: "bg-green-500" },
+ { label: "Agent Harness", dot: null },
+ { label: "MIT License", dot: null },
+ { label: "TypeScript 5.7", dot: null },
+ { label: "v1.5.0", dot: null },
+ ].map((b) => (
+
+ {b.dot && }
+ {b.label}
+
+ ))}
+
+
+ {/* Install command */}
+
+
+ One-command install
+
+
+
+
+
+
+ bash
+
+
+
+ $
+ {INSTALL_CMD}
+
+
+ {copied ? (
+
+ ) : (
+
+ )}
+
+
+
+
+
+ {/* Manual install */}
+
+ Or manually:{" "}
+ npm install -g @open-gitagent/gitagent
+
+
+ {/* CTAs */}
+
+
+ Get Started
+
+
+
+ Read Docs
+
+
+
+ GitHub
+
+
+
+
+ {/* Right — directory tree + agents-as-repos */}
+
+
+
+
+
+
+ your agent repo
+
+
+
+ {tree.map((item, i) => (
+
+ {item.icon}
+
+ {item.name}
+
+ {item.tag && (
+
+ {item.tag}
+
+ )}
+
+ ))}
+
+
+
+ {[
+ { cmd: "git fork org/base-agent", desc: "inherit personality + rules" },
+ { cmd: "git checkout -b feature/research-mode", desc: "experiment safely" },
+ { cmd: "git log memory/MEMORY.md", desc: "audit memory history" },
+ { cmd: "git diff SOUL.md", desc: "track personality changes" },
+ { cmd: "git revert HEAD~3", desc: "undo last 3 agent changes" },
+ { cmd: "git checkout v1.2.0", desc: "roll back to stable agent" },
+ ].map((line) => (
+
+ $
+ {line.cmd}
+ # {line.desc}
+
+ ))}
+
+
+
+
+
+
+
+ );
+}
diff --git a/src/components/gitAgent/GitAgentHooks.tsx b/src/components/gitAgent/GitAgentHooks.tsx
new file mode 100644
index 0000000..7ae7911
--- /dev/null
+++ b/src/components/gitAgent/GitAgentHooks.tsx
@@ -0,0 +1,242 @@
+import { motion } from "framer-motion";
+import { CodeBlock } from "@/components/gitAgent/CodeBlock";
+
+const hookEvents = [
+ {
+ event: "on_session_start",
+ when: "Before agent runs",
+ canBlock: true,
+ canModify: false,
+ },
+ {
+ event: "pre_tool_use",
+ when: "Before each tool call",
+ canBlock: true,
+ canModify: true,
+ },
+ {
+ event: "post_tool_failure",
+ when: "After a tool errors",
+ canBlock: false,
+ canModify: false,
+ },
+ {
+ event: "pre_query",
+ when: "Before LLM call",
+ canBlock: true,
+ canModify: false,
+ },
+ {
+ event: "post_response",
+ when: "After LLM responds",
+ canBlock: false,
+ canModify: false,
+ },
+ {
+ event: "file_changed",
+ when: "After file write",
+ canBlock: false,
+ canModify: false,
+ },
+ {
+ event: "on_error",
+ when: "On agent error",
+ canBlock: false,
+ canModify: false,
+ },
+];
+
+const hooksYaml = `hooks:
+ on_session_start:
+ - script:check-auth.sh
+ description: "Verify user authorization"
+
+ pre_tool_use:
+ - script:validate-command.sh
+ description: "Block dangerous CLI commands"
+
+ post_tool_failure:
+ - script:notify-error.sh
+
+ post_response:
+ - script:log-response.sh
+
+ pre_query:
+ - script:rate-limit.sh
+
+ file_changed:
+ - script:track-changes.sh
+
+ on_error:
+ - script:incident-report.sh`;
+
+const hookInput = `{
+ "event": "pre_tool_use",
+ "session_id": "uuid",
+ "tool": "cli",
+ "args": {"command": "rm -rf /"}
+}`;
+
+const hookOutput = `{"action": "allow"}
+{"action": "block", "reason": "Destructive command blocked"}
+{"action": "modify", "args": {"command": "echo safe"}}`;
+
+const sdkHooks = `for await (const msg of query({
+ prompt: "Deploy the service",
+ hooks: {
+ preToolUse: async (ctx) => {
+ if (ctx.toolName === "cli" && ctx.args.command?.includes("rm -rf"))
+ return { action: "block", reason: "Destructive command blocked" };
+ if (ctx.toolName === "write" && !ctx.args.path.startsWith("/safe/"))
+ return { action: "modify", args: { ...ctx.args, path: \`/safe/\${ctx.args.path}\` } };
+ return { action: "allow" };
+ },
+ onError: async (ctx) => {
+ console.error(\`Agent error: \${ctx.error}\`);
+ },
+ },
+})) { /* ... */ }`;
+
+function YesBadge() {
+ return (
+
+ Yes
+
+ );
+}
+
+function NoBadge() {
+ return (
+
+ No
+
+ );
+}
+
+export function GitAgentHooks() {
+ return (
+
+
+ {/* Section heading */}
+
+
+ Hooks
+
+
+ Lifecycle hooks let you intercept, block, or modify agent behavior at every stage —
+ via shell scripts or programmatic SDK callbacks.
+
+
+
+ {/* A. Hook Events */}
+
+
+ Hook Events
+
+
+ {/* Table header */}
+
+
+
+ {["Event", "When", "Can Block", "Can Modify"].map((col) => (
+
+ {col}
+
+ ))}
+
+
+ {hookEvents.map((row, i) => (
+
+
+ {row.event}
+
+
+ {row.when}
+
+ {row.canBlock ? : }
+ {row.canModify ? : }
+
+ ))}
+
+
+
+
+ {/* B. hooks.yaml config */}
+
+
+ hooks.yaml Config
+
+
+
+
+ {/* C. Hook Script Format — two code-blocks side by side */}
+
+
+ Hook Script Format
+
+
+ {/* Input */}
+
+
+ stdin (JSON input)
+
+
+
+
+ {/* Output */}
+
+
+ stdout (output options)
+
+
+
+
+
+
+ {/* D. Programmatic Hooks (SDK) */}
+
+
+ Programmatic Hooks (SDK)
+
+
+
+
+
+ );
+}
diff --git a/src/components/gitAgent/GitAgentInstallSection.tsx b/src/components/gitAgent/GitAgentInstallSection.tsx
new file mode 100644
index 0000000..2d0da21
--- /dev/null
+++ b/src/components/gitAgent/GitAgentInstallSection.tsx
@@ -0,0 +1,160 @@
+import { motion } from "framer-motion";
+import { ExternalLink } from "lucide-react";
+
+const installModes = [
+ {
+ mode: "Voice + Text",
+ command: "gitagent --voice",
+ desc: "Starts with voice mode and the web UI. Requires OPENAI_API_KEY or GEMINI_API_KEY.",
+ tag: "full",
+ },
+ {
+ mode: "Text Only",
+ command: "gitagent",
+ desc: "Text-only REPL, no voice or web UI. Works with any LLM provider key.",
+ tag: "lightweight",
+ },
+ {
+ mode: "Advanced / Custom",
+ command: "gitagent --dir ./my-agent",
+ desc: "Point to a custom agent.yaml for full control over model, tools, compliance, and identity.",
+ tag: "advanced",
+ },
+];
+
+export function GitAgentInstallSection() {
+ return (
+
+
+
+
+ 07 — Get Started
+
+
+ Launch & Install
+
+
+ Install once, then pick the launch mode that fits your workflow.
+
+
+
+
+ {/* Left: OpenGAP callout + requirements */}
+
+
+
+
+ Built on OpenGAP
+
+
+ GitAgent implements the{" "}
+ OpenGAP open standard — your agent definition
+ is portable, versionable, and exportable to any framework that speaks the protocol.
+
+
+
+ Learn about OpenGAP →
+
+
+
+
+ Requirements
+
+ {[
+ { label: "Node.js", value: "≥ 20" },
+ { label: "git", value: "any version" },
+ { label: "npm", value: "included with Node" },
+ { label: "Install", value: "npm install -g @open-gitagent/gitagent" },
+ ].map((r) => (
+
+ {r.label}
+ {r.value}
+
+ ))}
+
+
+
+ {/* CTAs */}
+
+
+ Read the Docs
+
+
+ View on GitHub →
+
+
+
+
+ {/* Right: launch modes */}
+
+
+ Launch Modes
+
+
+ {installModes.map((m, i) => (
+
+
+ {m.mode}
+
+ {m.tag}
+
+
+
+ $ {m.command}
+
+
+ {m.desc}
+
+
+ ))}
+
+
+
+
+
+ );
+}
diff --git a/src/components/gitAgent/GitAgentIntegrations.tsx b/src/components/gitAgent/GitAgentIntegrations.tsx
new file mode 100644
index 0000000..02740ac
--- /dev/null
+++ b/src/components/gitAgent/GitAgentIntegrations.tsx
@@ -0,0 +1,157 @@
+import { motion } from "framer-motion";
+import { Globe, MessageCircle, Smartphone, Phone } from "lucide-react";
+import { CodeBlock } from "@/components/gitAgent/CodeBlock";
+
+const composioCode = `# Set up Composio
+export COMPOSIO_API_KEY=your-key
+gitagent --voice --dir ~/assistant
+
+# Then in the Integrations tab, connect Gmail, Slack, GitHub, etc.
+# The agent will have access to those services as tools automatically`;
+
+const twilioWebhookCode = `Webhook URL: https://your-server:3333/api/phone/webhook`;
+
+export function GitAgentIntegrations() {
+ return (
+
+
+
+ Integrations
+
+ Connect GitAgent to external services via Composio, Telegram, WhatsApp, and Twilio.
+
+
+
+
+ {/* A. Composio card */}
+
+
+
+ Composio
+
+ 200+ integrations
+
+
+
+
+ Requires
+ COMPOSIO_API_KEY
+
+
+ Enables 200+ integrations: Gmail, Calendar, Slack, GitHub, Notion, Linear, Salesforce, and more.
+
+
+ Configure in the Integrations tab of the web UI.
+
+
+ GitAgent tools map directly to Composio actions.
+
+
+
+
+ {/* B. Telegram card */}
+
+
+
+ Telegram
+
+
+
+ Requires
+ TELEGRAM_BOT_TOKEN
+
+
+ {[
+ "Create bot via @BotFather → Enter token in Communication tab",
+ "Configure allowed users for access control",
+ "Files generated by the agent are auto-sent to Telegram",
+ "Used for approval gates in SkillFlows",
+ ].map((item, i) => (
+
+ ))}
+
+
+
+
+ {/* C. WhatsApp card */}
+
+
+
+ WhatsApp
+
+
+ {[
+ "Uses Baileys library — no phone number API needed",
+ "Connect via QR code in Communication tab",
+ "Session persists across restarts",
+ "Auto-responds to messages from your number",
+ ].map((item, i) => (
+
+ ))}
+
+
+
+ {/* D. Phone / SMS (Twilio) card */}
+
+
+
+
Phone / SMS (Twilio)
+
+
+
+ Configure this webhook URL in your Twilio console:
+
+
+
+
+
+
+ {/* E. Composio example */}
+
+
+ Composio Quick Start
+
+
+
+
+
+ );
+}
diff --git a/src/components/gitAgent/GitAgentIntegrationsSection.tsx b/src/components/gitAgent/GitAgentIntegrationsSection.tsx
new file mode 100644
index 0000000..e0a3df6
--- /dev/null
+++ b/src/components/gitAgent/GitAgentIntegrationsSection.tsx
@@ -0,0 +1,127 @@
+import { motion } from "framer-motion";
+import { Plug, MessageCircle, Phone, Smartphone } from "lucide-react";
+
+const integrations = [
+ {
+ icon: Plug,
+ name: "Composio",
+ tag: "200+ apps",
+ requirement: "COMPOSIO_API_KEY",
+ color: "text-blue-500",
+ desc: "Connect Gmail, Google Calendar, Slack, GitHub, Notion, Jira, and 200+ more services via the Composio toolkit. One key unlocks everything.",
+ features: ["Gmail & Calendar", "Slack & GitHub", "Notion & Jira", "CRM & payment tools"],
+ setup: `COMPOSIO_API_KEY=your_key
+# That's it — no agent.yaml changes needed.
+# Connect services in the Web UI Integrations tab.`,
+ },
+ {
+ icon: MessageCircle,
+ name: "Telegram",
+ tag: "BotFather",
+ requirement: "TELEGRAM_BOT_TOKEN",
+ color: "text-primary",
+ desc: "Create a bot via BotFather, add the token, and your agent is instantly reachable from Telegram — text, voice messages, and file sharing.",
+ features: ["Text & voice messages", "File sharing", "Group chat support", "Webhook or polling"],
+ setup: `TELEGRAM_BOT_TOKEN=your_token
+# That's it — no agent.yaml changes needed.
+# Configure allowed users via TELEGRAM_ALLOWED_USERS.`,
+ },
+ {
+ icon: Smartphone,
+ name: "WhatsApp",
+ tag: "Baileys QR",
+ requirement: "QR scan (no API key)",
+ color: "text-green-500",
+ desc: "Uses the Baileys library for direct WhatsApp connection. Scan a QR code from the Web UI Communication tab — no Meta API account needed.",
+ features: ["QR-based pairing", "No Meta API required", "Text & media", "Multi-device support"],
+ setup: `# No API key required
+# Go to Web UI → Communication tab
+# Scan QR code with WhatsApp`,
+ },
+ {
+ icon: Phone,
+ name: "Phone / SMS",
+ tag: "Twilio",
+ requirement: "Twilio phone number + webhook URL",
+ color: "text-orange-500",
+ desc: "Twilio webhook integration for inbound SMS and voice calls. Configure the webhook URL to your running agent and it handles phone interactions.",
+ features: ["Inbound SMS", "Voice call handling", "Webhook-based", "Twilio phone number"],
+ setup: `# In Twilio console:
+# Phone Numbers → your number → Messaging
+# Webhook URL: https://your-server:3333/api/phone/webhook`,
+ },
+];
+
+export function GitAgentIntegrationsSection() {
+ return (
+
+
+
+
+ 06 — Integrations
+
+
+ Integrations
+
+
+ Connect external services and reach your agent across every channel.
+
+
+
+
+ {integrations.map((item, i) => (
+
+ {/* Header */}
+
+
+ {item.name}
+
+ {item.tag}
+
+
+
+ {/* Requirement */}
+
+ Requires
+ {item.requirement}
+
+
+ {/* Description */}
+
+ {item.desc}
+
+
+ {/* Feature tags */}
+
+ {item.features.map((f) => (
+
+ {f}
+
+ ))}
+
+
+ {/* Setup snippet */}
+
+
+ ))}
+
+
+
+ );
+}
diff --git a/src/components/gitAgent/GitAgentInterfaces.tsx b/src/components/gitAgent/GitAgentInterfaces.tsx
new file mode 100644
index 0000000..e92091e
--- /dev/null
+++ b/src/components/gitAgent/GitAgentInterfaces.tsx
@@ -0,0 +1,105 @@
+import { motion } from "framer-motion";
+import { Terminal, Globe, MessageSquare, Code2 } from "lucide-react";
+import { CodeBlock } from "@/components/gitAgent/CodeBlock";
+
+const interfaces = [
+ {
+ icon: Terminal,
+ label: "CLI",
+ tagline: "Terminal REPL",
+ desc: "The primary way to run GitAgent. Launch an interactive session pointed at your agent repo.",
+ code: `gitagent --dir ~/assistant`,
+ filename: "terminal",
+ href: "/docs/cli",
+ },
+ {
+ icon: Globe,
+ label: "Web & Voice",
+ tagline: "Browser UI + microphone",
+ desc: "Start with the --voice flag to open a full browser interface at localhost:3333 — chat, skills, integrations, scheduler, and real-time voice.",
+ code: `gitagent --voice\n# opens localhost:3333`,
+ filename: "terminal",
+ href: "/docs/webui",
+ },
+ {
+ icon: MessageSquare,
+ label: "Messaging",
+ tagline: "Telegram · WhatsApp · Phone",
+ desc: "Connect your agent to Telegram or WhatsApp by setting the relevant env vars. Twilio adds phone (SMS/voice call) support.",
+ code: `TELEGRAM_BOT_TOKEN=your_token gitagent\n# WhatsApp: scan QR once in Web UI → auto-reconnects via .gitagent/whatsapp-auth/\n# Twilio: configure webhook URL in Twilio Console → your-server/api/phone/webhook`,
+ filename: ".env / terminal",
+ href: "/docs/messaging",
+ },
+ {
+ icon: Code2,
+ label: "SDK",
+ tagline: "Embed in Node.js",
+ desc: "Import GitAgent directly into your application. Use query() to send a prompt and get a response programmatically.",
+ code: `import { query } from "@open-gitagent/gitagent";\n\nfor await (const msg of query({\n prompt: "Summarise yesterday's tasks",\n dir: "./my-agent",\n})) {\n if (msg.type === "assistant") console.log(msg.content);\n}`,
+ filename: "app.ts",
+ href: "/docs/sdk",
+ },
+];
+
+export function GitAgentInterfaces() {
+ return (
+
+
+
+
+ Ways to Interact
+
+
+ GitAgent meets you where you work — terminal, browser, chat app, or embedded in your own code.
+
+
+
+
+ {interfaces.map((iface, i) => {
+ const Icon = iface.icon;
+ return (
+
+
+
+
+
+
+
+ {iface.label}
+ {iface.tagline}
+
+
{iface.desc}
+
+
+
+
+
+
+
+ );
+ })}
+
+
+
+
+ );
+}
diff --git a/src/components/gitAgent/GitAgentMemory.tsx b/src/components/gitAgent/GitAgentMemory.tsx
new file mode 100644
index 0000000..f7e0e45
--- /dev/null
+++ b/src/components/gitAgent/GitAgentMemory.tsx
@@ -0,0 +1,187 @@
+import { motion } from "framer-motion";
+import { SmilePlus, Camera, BookOpen, Brain } from "lucide-react";
+import { CodeBlock } from "@/components/gitAgent/CodeBlock";
+
+const layersYaml = `# memory/memory.yaml
+layers:
+ - name: working
+ path: memory/MEMORY.md
+ max_lines: 1000
+ format: markdown
+ - name: technical
+ path: memory/technical.md
+ max_lines: 500
+ format: markdown
+
+archive_policy:
+ max_entries: 500
+ compress_after: 30d`;
+
+const memoryTree = `memory/
+├── MEMORY.md # Primary memory (versioned)
+├── mood.md # Per-session mood log
+├── photos/ # Camera captures
+│ └── 2025-08-28-moment.jpg
+├── journal/ # Session reflections
+│ └── 2025-08-28.md
+└── archive/ # Auto-archived old entries
+ └── 2025-07-archive.md`;
+
+const memoryCommandsCode = `# View current memory in REPL
+/memory
+
+# Full git history of every memory write
+git log --oneline memory/MEMORY.md
+
+# Diff what changed last session
+git diff HEAD~1 memory/MEMORY.md
+
+# Undo a specific memory commit
+git revert a3f2e91
+
+# Read yesterday's mood log
+git show HEAD:memory/mood.md
+
+# Save something to memory via SDK
+query({ prompt: "Remember that the API base URL is https://api.example.com", dir: "./my-agent" })`;
+
+const additionalFeatures = [
+ {
+ icon: SmilePlus,
+ label: "Mood Log",
+ path: "memory/mood.md",
+ desc: "Session mood tracking (happy, frustrated, curious, excited, calm)",
+ },
+ {
+ icon: Camera,
+ label: "Photos",
+ path: "memory/photos/",
+ desc: "Captured memorable moments with INDEX.md",
+ },
+ {
+ icon: BookOpen,
+ label: "Journal",
+ path: "memory/journal/.md",
+ desc: "Auto-generated session reflections",
+ },
+ {
+ icon: Brain,
+ label: "Learning",
+ path: ".gitagent/learning/",
+ desc: "Task history and learned skills (JSON)",
+ },
+];
+
+export function GitAgentMemory() {
+ return (
+
+
+
+ Memory
+
+ Git-native memory — all changes are committed, versioned, and auditable.
+
+
+
+ {/* A. Overview card */}
+
+
+
+ GitAgent's memory is git-native — all memory changes are committed, versioned, and auditable.{" "}
+ memory/MEMORY.md is the primary memory file,
+ loaded into every conversation.
+
+
+
+
+
+ {/* B. Directory tree */}
+
+
+ Directory Structure
+
+
+
+
+ {/* C. Memory Layers config */}
+
+
+ Memory Layers
+
+
+
+ When a layer exceeds max_lines, old entries are
+ auto-archived to{" "}
+ memory/archive/<YYYY-MM>.md
+
+
+
+
+ {/* C. Additional Memory Features */}
+
+
+ Additional Memory Features
+
+
+ {additionalFeatures.map((f, i) => {
+ const Icon = f.icon;
+ return (
+
+
+
+ {f.label}
+
+ {f.path}
+ {f.desc}
+
+ );
+ })}
+
+
+
+ {/* E. Memory commands */}
+
+
+ Memory Commands
+
+
+
+
+
+ );
+}
diff --git a/src/components/gitAgent/GitAgentMemorySection.tsx b/src/components/gitAgent/GitAgentMemorySection.tsx
new file mode 100644
index 0000000..96cd3a3
--- /dev/null
+++ b/src/components/gitAgent/GitAgentMemorySection.tsx
@@ -0,0 +1,75 @@
+import { motion } from "framer-motion";
+import { Archive, Camera, BookOpen, Zap } from "lucide-react";
+
+const memoryFeatures = [
+ {
+ icon: Archive,
+ title: "Auto-Archiving",
+ desc: "When a layer exceeds max_lines, oldest entries are moved to memory/archive/.md — keeping MEMORY.md fast without losing history.",
+ color: "text-blue-500",
+ },
+ {
+ icon: BookOpen,
+ title: "Mood & Journal",
+ desc: "Per-session mood log (mood.md) and voice session reflection journal in memory/journal/ — both committed to git.",
+ color: "text-orange-500",
+ },
+ {
+ icon: Camera,
+ title: "Photos & Moments",
+ desc: "Voice mode captures webcam frames during memorable moments and stores them in memory/photos/ with a git commit.",
+ color: "text-purple-500",
+ },
+ {
+ icon: Zap,
+ title: "Learning",
+ desc: "Completed tasks are crystallized into reusable skills in .gitagent/learning/ — the agent improves over time.",
+ color: "text-primary",
+ },
+];
+
+export function GitAgentMemorySection() {
+ return (
+
+
+
+
+ 05 — Memory
+
+
+ Git-Native Memory
+
+
+ Every memory write is a git commit. Memory lives in plain Markdown files — readable, diffable, and rollback-able at any time.
+
+
+
+
+ {memoryFeatures.map((f, i) => (
+
+
+
+ {f.title}
+
+
+ {f.desc}
+
+
+ ))}
+
+
+
+ );
+}
diff --git a/src/components/gitAgent/GitAgentMessaging.tsx b/src/components/gitAgent/GitAgentMessaging.tsx
new file mode 100644
index 0000000..5d6d169
--- /dev/null
+++ b/src/components/gitAgent/GitAgentMessaging.tsx
@@ -0,0 +1,127 @@
+import { motion } from "framer-motion";
+import { Send, Smartphone, Phone } from "lucide-react";
+import { CodeBlock } from "@/components/gitAgent/CodeBlock";
+
+export function GitAgentMessaging() {
+ return (
+
+
+
+ Messaging
+
+ Connect your agent to Telegram, WhatsApp, and phone — all through the same running instance.
+
+
+
+
+
+ {/* Telegram */}
+
+
+
+ Set TELEGRAM_BOT_TOKEN and the agent automatically becomes a Telegram bot. No extra config needed.
+
+
+
+
+
+
+ {/* WhatsApp */}
+
+
+
+ WhatsApp has no env var toggle. Set it up once through the Web UI — credentials persist automatically after that.
+
+
+ {[
+ <>Start gitagent --voice>,
+ <>Open localhost:3333 → go to Integrations → scan the QR code>,
+ <>Credentials are saved to .gitagent/whatsapp-auth/creds.json>,
+ <>On every subsequent start, WhatsApp auto-reconnects if that file exists>,
+ ].map((step, i) => (
+
+
+ {i + 1}
+
+ {step}
+
+ ))}
+
+
+
+ {/* Phone (Twilio) */}
+
+
+
+
+ Phone
+ via Twilio
+
+
+
+ GitAgent does not read TWILIO_ACCOUNT_SID or TWILIO_AUTH_TOKEN. Setup is done entirely in the Twilio Console.
+
+
+ {[
+ <>Start gitagent --voice>,
+ <>In the Twilio Console, set your webhook URL to your server's phone endpoint>,
+ <>Incoming calls are routed to the agent automatically>,
+ ].map((step, i) => (
+
+
+ {i + 1}
+
+ {step}
+
+ ))}
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/src/components/gitAgent/GitAgentModels.tsx b/src/components/gitAgent/GitAgentModels.tsx
new file mode 100644
index 0000000..56ca1a6
--- /dev/null
+++ b/src/components/gitAgent/GitAgentModels.tsx
@@ -0,0 +1,275 @@
+import { useState } from "react";
+import { motion } from "framer-motion";
+import { Copy, Check } from "lucide-react";
+import { CodeBlock } from "@/components/gitAgent/CodeBlock";
+
+const providers = [
+ { name: "Anthropic", example: "anthropic:claude-sonnet-4-6", envVar: "ANTHROPIC_API_KEY" },
+ { name: "OpenAI", example: "openai:gpt-4o", envVar: "OPENAI_API_KEY" },
+ { name: "Google", example: "google:gemini-2.0-flash-001", envVar: "GOOGLE_API_KEY" },
+ { name: "Groq", example: "groq:llama-3.3-70b-versatile", envVar: "GROQ_API_KEY" },
+ { name: "xAI", example: "xai:grok-2-1212", envVar: "XAI_API_KEY" },
+ { name: "Mistral", example: "mistral:mistral-large-latest", envVar: "MISTRAL_API_KEY" },
+ { name: "OpenRouter", example: "openrouter:anthropic/claude-3.5-sonnet", envVar: "OPENROUTER_API_KEY" },
+ { name: "Cerebras", example: "cerebras:llama3.1-70b", envVar: "CEREBRAS_API_KEY" },
+ { name: "DeepSeek", example: "deepseek:deepseek-chat", envVar: "DEEPSEEK_API_KEY" },
+ { name: "Amazon Bedrock", example: "amazon-bedrock:anthropic.claude-3-sonnet", envVar: "AWS credentials" },
+ { name: "Google Vertex", example: "google-vertex:gemini-2.5-flash", envVar: "GCP ADC" },
+ { name: "Azure OpenAI", example: "azure-openai-responses:gpt-4o", envVar: "AZURE_OPENAI_API_KEY" },
+];
+
+const resolutionSteps = [
+ {
+ step: 1,
+ label: "Environment config model_override",
+ detail: "from config/.yaml",
+ },
+ {
+ step: 2,
+ label: "CLI flag --model provider:model-id",
+ detail: "passed at runtime",
+ },
+ {
+ step: 3,
+ label: "agent.yaml model.preferred",
+ detail: "defined in the agent repo",
+ },
+];
+
+const customEndpointCode = `# Inline URL
+gitagent --model "ollama:llama3@http://localhost:11434/v1" --voice --dir ~/assistant
+
+# Environment variable
+export GITAGENT_MODEL_BASE_URL=http://localhost:11434/v1
+gitagent --model "ollama:llama3" --voice --dir ~/assistant
+
+# In agent.yaml
+# model:
+# preferred: "custom:my-model@https://my-proxy.com/v1"`;
+
+const compatibleEndpoints = [
+ { name: "Ollama", port: "11434" },
+ { name: "LM Studio", port: "1234" },
+ { name: "vLLM", port: "8000" },
+ { name: "LiteLLM", port: "4000" },
+ { name: "Lyzr AI Studio", port: "" },
+ { name: "Any OpenAI-compatible proxy", port: "" },
+];
+
+const lyzrSdkCode = `import { query } from "@open-gitagent/gitagent";
+
+const result = query({
+ prompt: "Hello! What can you help me with?",
+ dir: "/path/to/agent",
+ model: \`lyzr:\${LYZR_AGENT_ID}@https://agent-prod.studio.lyzr.ai/v4\`,
+ constraints: { temperature: 0.7, maxTokens: 2000 },
+});
+for await (const msg of result) {
+ if (msg.type === "assistant") console.log(msg.content);
+}`;
+
+const lyzrOptions = [
+ { label: "Via installer (easiest)", desc: "Run the interactive installer and select Lyzr when prompted" },
+ { label: "Via CLI flag", desc: `gitagent --model "lyzr:@https://agent-prod.studio.lyzr.ai/v4" --dir ~/assistant` },
+ { label: "Via SDK", desc: "Use the query() function with a lyzr: model string (see example below)" },
+];
+
+export function GitAgentModels() {
+ const [copiedEndpoint, setCopiedEndpoint] = useState(false);
+
+ const handleCopyEndpoint = () => {
+ navigator.clipboard.writeText(customEndpointCode);
+ setCopiedEndpoint(true);
+ setTimeout(() => setCopiedEndpoint(false), 2000);
+ };
+ return (
+
+
+ {/* Section heading */}
+
+
+ Models & Providers
+
+
+ 12 providers out of the box. Custom endpoints and OpenAI-compatible proxies supported.
+
+
+
+ {/* A. Providers grid — 3 cols on lg */}
+
+
+ Supported Providers
+
+
+ {providers.map((p, i) => (
+
+
+
+ {p.name}
+
+
+ {p.envVar}
+
+
+
+ {p.example}
+
+
+ ))}
+
+
+
+ {/* B. Model resolution order */}
+
+
+ Model Resolution Order
+
+
+ {resolutionSteps.map((s, i) => (
+
+
+ {s.step}
+
+
+
+ {s.label}
+
+
+ — {s.detail}
+
+
+
+ ))}
+
+
+
+ {/* C. Custom / OpenAI-Compatible Endpoints */}
+
+
+ Custom / OpenAI-Compatible Endpoints
+
+
+
+
+
+
+ terminal
+
+ {copiedEndpoint ? : }
+
+
+
+ {customEndpointCode.split("\n").map((line, i) => (
+
+ {line}
+
+ ))}
+
+
+
+ {compatibleEndpoints.map((ep) => (
+
+ {ep.name}
+ {ep.port && (
+ :{ep.port}
+ )}
+
+ ))}
+
+
+
+ {/* D. Lyzr Integration */}
+
+
+
+
+ Lyzr AI Studio Integration
+
+
+ Connect to Lyzr's managed agent infrastructure. Your agent runs on Lyzr's servers with full observability.
+
+
+
+ {lyzrOptions.map((opt, i) => (
+
+
+ {opt.label}
+
+ {opt.label === "Via CLI flag" ? (
+
+ {opt.desc}
+
+ ) : (
+
+ {opt.desc}
+
+ )}
+
+ ))}
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/src/components/gitAgent/GitAgentModelsSection.tsx b/src/components/gitAgent/GitAgentModelsSection.tsx
new file mode 100644
index 0000000..f44cde1
--- /dev/null
+++ b/src/components/gitAgent/GitAgentModelsSection.tsx
@@ -0,0 +1,64 @@
+import { motion } from "framer-motion";
+
+const providers = [
+ { name: "Anthropic", format: "anthropic:", envKey: "ANTHROPIC_API_KEY" },
+ { name: "OpenAI", format: "openai:", envKey: "OPENAI_API_KEY" },
+ { name: "Google", format: "google:", envKey: "GEMINI_API_KEY" },
+ { name: "Groq", format: "groq:", envKey: "GROQ_API_KEY" },
+ { name: "xAI", format: "xai:", envKey: "XAI_API_KEY" },
+ { name: "Mistral", format: "mistral:", envKey: "MISTRAL_API_KEY" },
+ { name: "OpenRouter", format: "openrouter:", envKey: "OPENROUTER_API_KEY" },
+ { name: "Cerebras", format: "cerebras:", envKey: "CEREBRAS_API_KEY" },
+ { name: "DeepSeek", format: "deepseek:", envKey: "DEEPSEEK_API_KEY" },
+ { name: "AWS Bedrock", format: "amazon-bedrock:", envKey: "AWS_ACCESS_KEY_ID" },
+ { name: "Google Vertex", format: "google-vertex:", envKey: "GOOGLE_APPLICATION_CREDENTIALS" },
+ { name: "Azure OpenAI", format: "azure-openai-responses:", envKey: "AZURE_OPENAI_API_KEY" },
+];
+
+export function GitAgentModelsSection() {
+ return (
+
+
+
+
+ 04 — Models
+
+
+ 12+ Model Providers
+
+
+ Switch providers by changing one env var. Any OpenAI-compatible endpoint works too.
+
+
+
+
+ {providers.map((p, i) => (
+
+
+ {p.name}
+
+
+ {p.format}
+
+
+ {p.envKey}
+
+
+ ))}
+
+
+
+ );
+}
diff --git a/src/components/gitAgent/GitAgentNavbar.tsx b/src/components/gitAgent/GitAgentNavbar.tsx
new file mode 100644
index 0000000..c0a902d
--- /dev/null
+++ b/src/components/gitAgent/GitAgentNavbar.tsx
@@ -0,0 +1,191 @@
+import { useState, useRef, useEffect } from "react";
+import { Menu, X, Search, Github } from "lucide-react";
+import { Sheet, SheetContent, SheetTrigger } from "@/components/ui/sheet";
+import { sidebarGroups } from "@/components/gitAgent/GitAgentSidebar";
+
+const allItems = sidebarGroups.flatMap((g) =>
+ g.items.map((item) => ({ ...item, group: g.label, slug: g.slug }))
+);
+
+interface GitAgentNavbarProps {
+ variant?: "overview" | "docs" | "subpage";
+}
+
+export function GitAgentNavbar({ variant = "docs" }: GitAgentNavbarProps) {
+ const [sheetOpen, setSheetOpen] = useState(false);
+ const [query, setQuery] = useState("");
+ const [searchOpen, setSearchOpen] = useState(false);
+ const searchRef = useRef(null);
+
+ useEffect(() => {
+ function handleClickOutside(e: MouseEvent) {
+ if (searchRef.current && !searchRef.current.contains(e.target as Node)) {
+ setSearchOpen(false);
+ }
+ }
+ document.addEventListener("mousedown", handleClickOutside);
+ return () => document.removeEventListener("mousedown", handleClickOutside);
+ }, []);
+
+ const filtered = query
+ ? allItems.filter((item) =>
+ item.label.toLowerCase().includes(query.toLowerCase()) ||
+ item.group.toLowerCase().includes(query.toLowerCase())
+ )
+ : allItems;
+
+ return (
+
+
+ {/* Left: back + Logo + version badge */}
+
+ {(variant === "subpage" || variant === "docs") && (
+
+ ←
+
+ )}
+
+ Git Agent
+
+
+ v1.5.0
+
+
+
+ {/* Middle: search — docs only, desktop */}
+ {variant === "docs" && (
+
+
+
+ setQuery(e.target.value)}
+ onFocus={() => setSearchOpen(true)}
+ placeholder="Search docs…"
+ className="text-xs font-body bg-transparent outline-none text-foreground placeholder:text-muted-foreground/40 w-full"
+ />
+ {query && (
+ setQuery("")}
+ className="text-muted-foreground/50 hover:text-foreground transition-colors shrink-0"
+ aria-label="Clear search"
+ >
+
+
+ )}
+
+
+ {searchOpen && (
+
+ {filtered.length === 0 ? (
+
No results
+ ) : (
+
+ )}
+
+ )}
+
+ )}
+
+ {/* Right — desktop */}
+
+
+ {/* Mobile right */}
+
+ {variant === "docs" ? (
+
+
+
+ {sheetOpen ? : }
+
+
+
+
+ Git Agent
+ docs
+
+
+ {sidebarGroups.map((group, groupIndex) => (
+
+ ))}
+
+
+
+
+ ) : (
+
+ GitHub
+
+ )}
+
+
+
+ );
+}
diff --git a/src/components/gitAgent/GitAgentOverview.tsx b/src/components/gitAgent/GitAgentOverview.tsx
new file mode 100644
index 0000000..fae7072
--- /dev/null
+++ b/src/components/gitAgent/GitAgentOverview.tsx
@@ -0,0 +1,219 @@
+import { motion } from "framer-motion";
+
+const repoPhilosophyItems = [
+ {
+ file: "agent.yaml",
+ desc: "model, tools, runtime config",
+ dot: "bg-primary",
+ },
+ {
+ file: "SOUL.md",
+ desc: "personality and identity",
+ dot: "bg-primary/70",
+ },
+ {
+ file: "RULES.md",
+ desc: "behavioral constraints",
+ dot: "bg-foreground/40",
+ },
+ {
+ file: "memory/",
+ desc: "git-committed memory with full history",
+ dot: "bg-primary/50",
+ },
+ {
+ file: "tools/ + skills/ + hooks/",
+ desc: "all version-controlled",
+ dot: "bg-foreground/30",
+ },
+];
+
+const comparisonRows = [
+ {
+ dimension: "Primary purpose",
+ gitagent: "General-purpose AI agent framework",
+ openclaw: "General-purpose life/work assistant",
+ },
+ {
+ dimension: "Security model",
+ gitagent: "Git-native (all changes tracked, reversible), auditable",
+ openclaw:
+ "Auth disabled by default, plaintext credentials, vulnerable skill marketplace",
+ },
+ {
+ dimension: "Voice mode",
+ gitagent:
+ "Real-time bidirectional with OpenAI Realtime API, camera input",
+ openclaw: "TTS/STT via ElevenLabs, no real-time bidirectional",
+ },
+ {
+ dimension: "Skills",
+ gitagent:
+ "Curated marketplace, agent creates its own skills, SkillFlow",
+ openclaw: "13,700+ community skills (~20% flagged malicious)",
+ },
+ {
+ dimension: "Memory",
+ gitagent: "Structured git-committed memory with RL + archival",
+ openclaw: "Markdown diary entries",
+ },
+ {
+ dimension: "Multi-channel",
+ gitagent: "Voice UI, Telegram, WhatsApp",
+ openclaw: "20+ channels",
+ },
+ {
+ dimension: "Architecture",
+ gitagent: "Single focused process, SDK for embedding",
+ openclaw: "Gateway + multiple services",
+ },
+];
+
+export function GitAgentOverview() {
+ return (
+
+ {/* Brief intro */}
+
+
+ Overview
+
+
+ GitAgent is a git-native, multimodal AI agent harness built in TypeScript. Your agent lives entirely inside a git repository — identity, memory, rules, tools, and skills are all plain files you can read, diff, and roll back.
+ Install with one command, configure in plain text, and run it anywhere Node.js runs.
+
+
+
+ {/* Why GitAgent heading */}
+
+
+ Why GitAgent
+
+
+ Agents as repos — your agent IS a git repository.
+
+
+
+ {/* Two-column: repo philosophy + narrower scope note */}
+
+ {/* Left: repo philosophy */}
+
+
+ Your agent repo
+
+
+ {repoPhilosophyItems.map((item) => (
+
+
+
+ {item.file}
+ — {item.desc}
+
+
+ ))}
+
+
+ Fork an agent. Branch a personality.{" "}
+ git log your agent's memory.{" "}
+ diff its rules. This is agents as repos.
+
+
+
+ {/* Right: scope note */}
+
+
+ Design philosophy
+
+
+ GitAgent is narrower in scope but deeper in execution.
+
+
+ Rather than being a general-purpose life assistant, GitAgent focuses entirely on
+ being the best autonomous coding and project agent possible. Every design decision
+ optimizes for reliability, security, and developer trust.
+
+
+ {[
+ "All agent state is version-controlled",
+ "No silent credential storage",
+ "Auditable by design",
+ "Composable skills via SkillFlow",
+ ].map((point) => (
+
+
+ {point}
+
+ ))}
+
+
+
+
+ {/* Comparison table */}
+
+
+ {/* Table header */}
+
+ {["Dimension", "GitAgent", "OpenClaw"].map((col) => (
+
+ {col}
+
+ ))}
+
+
+ {/* Table rows */}
+ {comparisonRows.map((row, i) => (
+
+
+ {row.dimension}
+
+
+ {row.gitagent}
+
+
+ {row.openclaw}
+
+
+ ))}
+
+
+
+
+ );
+}
diff --git a/src/components/gitAgent/GitAgentPlugins.tsx b/src/components/gitAgent/GitAgentPlugins.tsx
new file mode 100644
index 0000000..99ffe58
--- /dev/null
+++ b/src/components/gitAgent/GitAgentPlugins.tsx
@@ -0,0 +1,176 @@
+import { motion } from "framer-motion";
+import { Wrench, Zap, MessageSquare, GitBranch, Database } from "lucide-react";
+import { CodeBlock } from "@/components/gitAgent/CodeBlock";
+
+const manifestYaml = `id: my-plugin
+name: My Plugin
+version: 1.0.0
+description: What this plugin does
+author: Your Name
+license: MIT
+engine: ">=1.0.0"
+
+provides:
+ tools: true
+ skills: true
+ prompt: prompt.md
+ hooks:
+ pre_tool_use:
+ - script: hooks/validate.sh # any filename — hooks.yaml points to it`;
+
+const structureCode = `plugins/my-plugin/
+ plugin.yaml # manifest
+ prompt.md # appended to system prompt
+ tools/
+ my-tool.yaml # declarative tools
+ skills/
+ my-skill/
+ SKILL.md
+ hooks/
+ validate.sh # example — any filename, referenced from hooks.yaml`;
+
+const managementCode = `# Install from git URL
+gitagent plugin install https://github.com/user/plugin
+# Install from local path
+gitagent plugin install ./path/to/plugin
+# List all plugins
+gitagent plugin list
+# Enable / disable
+gitagent plugin enable my-plugin
+gitagent plugin disable my-plugin
+# Remove
+gitagent plugin remove my-plugin
+# Scaffold new plugin
+gitagent plugin init my-plugin`;
+
+const agentYamlConfig = `plugins:
+ my-plugin:
+ enabled: true
+ config:
+ api_key: "your-api-key"
+ timeout: 30`;
+
+const sdkCode = `import type { GitagentPluginApi } from "@open-gitagent/gitagent";
+
+export function register(api: GitagentPluginApi) {
+ api.registerTool(myTool);
+ api.registerHook("pre_tool_use", async (ctx) => ({ action: "allow" }));
+ api.addPrompt("Additional context for the agent...");
+}`;
+
+const provisions = [
+ { icon: Wrench, label: "Tools", desc: "Expose new typed tools to the agent" },
+ { icon: Zap, label: "Skills", desc: "Add reusable skill definitions" },
+ { icon: MessageSquare, label: "System Prompt Injection", desc: "Append context via prompt.md" },
+ { icon: GitBranch, label: "Lifecycle Hooks", desc: "React to tool use and session events" },
+ { icon: Database, label: "Memory Layers", desc: "Add scoped memory files" },
+];
+
+export function GitAgentPlugins() {
+ return (
+
+
+
+ Plugin System
+
+ Extend GitAgent with installable plugins that provide tools, skills, hooks, and memory layers.
+
+
+
+
+ {/* A. Plugin Manifest */}
+
+
+ Plugin Manifest
+
+
+
+
+ {/* B. Plugin Structure */}
+
+
+ Plugin Structure
+
+
+
+ {/* D. agent.yaml plugin config */}
+
+ agent.yaml Plugin Config
+
+
+
+
+
+ {/* C. Plugin Management CLI */}
+
+
+ Plugin Management CLI
+
+
+
+
+ {/* E. Programmatic Plugin (SDK) */}
+
+
+ Programmatic Plugin (SDK)
+
+
+
+
+ {/* F. What plugins can provide */}
+
+
+ What Plugins Can Provide
+
+
+ {provisions.map((p, i) => {
+ const Icon = p.icon;
+ return (
+
+
+ {p.label}
+ {p.desc}
+
+ );
+ })}
+
+
+
+
+ );
+}
diff --git a/src/components/gitAgent/GitAgentQuickStart.tsx b/src/components/gitAgent/GitAgentQuickStart.tsx
new file mode 100644
index 0000000..5dbdb0e
--- /dev/null
+++ b/src/components/gitAgent/GitAgentQuickStart.tsx
@@ -0,0 +1,212 @@
+import { motion } from "framer-motion";
+import { Info } from "lucide-react";
+import { CodeBlock } from "@/components/gitAgent/CodeBlock";
+
+const installMethods = [
+ {
+ title: "Interactive installer (recommended)",
+ code: `curl -fsSL https://raw.githubusercontent.com/open-gitagent/gitagent/main/install.sh | bash`,
+ desc: "Installs globally via npm, walks through API key setup, launches web UI at http://localhost:3333",
+ },
+ {
+ title: "Manual install",
+ code: `npm install -g @open-gitagent/gitagent
+mkdir ~/assistant && cd ~/assistant && git init
+gitagent --voice --dir .`,
+ desc: "",
+ },
+];
+
+const setupModes = [
+ {
+ name: "Install with LYZR",
+ desc: "Easiest — uses Lyzr AI Studio cloud",
+ keys: "LYZR_API_KEY",
+ },
+ {
+ name: "Voice + Text",
+ desc: "Real-time voice + text chat",
+ keys: "OPENAI_API_KEY (or GEMINI_API_KEY for --voice gemini)",
+ },
+ {
+ name: "Text Only",
+ desc: "Terminal REPL, no voice or web UI",
+ keys: "ANTHROPIC_API_KEY",
+ },
+ {
+ name: "Advanced Setup",
+ desc: "Choose voice adapter, model, port, integrations",
+ keys: "varies",
+ },
+];
+
+const quickExamples = [
+ {
+ comment: "# Single-shot query",
+ code: `gitagent --dir ~/my-project "Build a REST API for user management"`,
+ },
+ {
+ comment: "# With voice UI",
+ code: `gitagent --voice --dir ~/assistant`,
+ },
+ {
+ comment: "# Local repo mode — clone, fix, commit to session branch",
+ code: `gitagent --repo https://github.com/org/repo --pat ghp_xxx "Fix the login bug"`,
+ },
+];
+
+export function GitAgentQuickStart() {
+ return (
+
+
+ {/* Section heading */}
+
+
+ Quick Start
+
+
+ Install, configure, and run your first agent in minutes.
+
+
+
+ {/* A. Install methods */}
+
+
+ Installation
+
+
+ {installMethods.map((method, i) => (
+
+
+ {method.title}
+
+
+ {method.desc && (
+
+ {method.desc}
+
+ )}
+
+ ))}
+
+
+
+ {/* B. Setup Modes — 2×2 grid */}
+
+
+ Setup Modes
+
+
+ {setupModes.map((mode, i) => (
+
+
+
+ {mode.name}
+
+
+ {mode.desc}
+
+
+ {mode.keys}
+
+
+
+ ))}
+
+
+
+ {/* C. First run note */}
+
+
+
+
+
+ Auto-scaffold on first run:
+
+ gitagent --dir ~/my-project 'Explain this project'
+ {" "}
+ auto-creates agent.yaml,{" "}
+ SOUL.md, and{" "}
+ memory/ in the target directory.
+
+
+
+
+
+ {/* D. Quick examples */}
+
+
+ Quick Examples
+
+
+
+
+
+
+
+ terminal
+
+
+
+ {quickExamples.map((ex, i) => (
+
+
+ {ex.comment}
+
+
+ {ex.code}
+
+
+ ))}
+
+
+
+
+
+ );
+}
diff --git a/src/components/gitAgent/GitAgentSDK.tsx b/src/components/gitAgent/GitAgentSDK.tsx
new file mode 100644
index 0000000..b264e28
--- /dev/null
+++ b/src/components/gitAgent/GitAgentSDK.tsx
@@ -0,0 +1,305 @@
+import { useState } from "react";
+import { motion } from "framer-motion";
+import { Copy, Check } from "lucide-react";
+import { track } from "@/lib/analytics";
+import { CodeBlock } from "@/components/gitAgent/CodeBlock";
+
+const tabs = ["query()", "tool()", "buildTool()", "hooks"] as const;
+type Tab = (typeof tabs)[number];
+
+const codeMap: Record = {
+ "query()": `import { query } from "@open-gitagent/gitagent";
+
+for await (const msg of query({
+ prompt: "Refactor the auth module",
+ dir: "/path/to/agent",
+ model: "anthropic:claude-sonnet-4-6",
+})) {
+ switch (msg.type) {
+ case "delta": // streaming text chunk
+ process.stdout.write(msg.content); break;
+ case "assistant": // complete response
+ console.log(\`\\nTokens: \${msg.usage?.totalTokens}\`); break;
+ case "tool_use": // tool invocation
+ console.log(\`Tool: \${msg.toolName}(\${JSON.stringify(msg.args)})\`); break;
+ case "tool_result": // tool output
+ console.log(\`Result: \${msg.content}\`); break;
+ case "system": // lifecycle events & errors
+ console.log(\`[\${msg.subtype}] \${msg.content}\`); break;
+ }
+}`,
+ "tool()": `import { query, tool } from "@open-gitagent/gitagent";
+
+const search = tool(
+ "search_docs",
+ "Search the documentation",
+ {
+ properties: {
+ query: { type: "string", description: "Search query" },
+ limit: { type: "number", description: "Max results" },
+ },
+ required: ["query"],
+ },
+ async (args) => {
+ const results = await mySearchEngine(args.query, args.limit ?? 10);
+ return { text: JSON.stringify(results), details: { count: results.length } };
+ },
+);
+
+for await (const msg of query({ prompt: "Find auth docs", tools: [search] })) {
+ // agent can now call search_docs
+}`,
+ "buildTool()": `import { buildTool } from "@open-gitagent/gitagent";
+
+const myTool = buildTool({
+ name: "search_docs",
+ description: "Search documentation",
+ parameters: {
+ properties: { query: { type: "string" } },
+ required: ["query"],
+ },
+ execute: async (args) => {
+ return "Results: ...";
+ },
+ metadata: {
+ isConcurrencySafe: true, // safe to run in parallel
+ isReadOnly: true, // no side effects
+ maxResultSizeChars: 20000, // truncate large results
+ },
+});`,
+ hooks: `const result = query({
+ prompt: "Deploy to production",
+ dir: "/path/to/agent",
+ hooks: {
+ onSessionStart: async (ctx) => ({ action: "allow" }),
+ preToolUse: async (ctx) => {
+ if (ctx.toolName === "cli" && ctx.args.command.includes("deploy")) {
+ return { action: "block", reason: "Manual approval required" };
+ }
+ return { action: "allow" };
+ },
+ postToolFailure: async (ctx) => {
+ console.error(\`Tool \${ctx.toolName} failed: \${ctx.error}\`);
+ },
+ preQuery: async (ctx) => {
+ console.log(\`Sending prompt to LLM: \${ctx.sessionId}\`);
+ return { action: "allow" };
+ },
+ postResponse: async (ctx) => {
+ console.log(\`Session \${ctx.sessionId} responded\`);
+ },
+ fileChanged: async (ctx) => {
+ console.log(\`File changed: \${ctx.path}\`);
+ },
+ onError: async (ctx) => {
+ console.error(\`Error in \${ctx.sessionId}: \${ctx.error}\`);
+ },
+ },
+});`,
+};
+
+const queryOptions = [
+ { name: "prompt", type: "string | AsyncIterable", desc: "User prompt or multi-turn stream" },
+ { name: "dir", type: "string", desc: "Agent directory (default: cwd)" },
+ { name: "model", type: "string", desc: '"provider:model-id"' },
+ { name: "env", type: "string", desc: "Environment config (config/.yaml)" },
+ { name: "systemPrompt", type: "string", desc: "Override discovered system prompt" },
+ { name: "systemPromptSuffix", type: "string", desc: "Append to discovered system prompt" },
+ { name: "tools", type: "GCToolDefinition[]", desc: "Additional tools" },
+ { name: "replaceBuiltinTools", type: "boolean", desc: "Skip cli/read/write/memory" },
+ { name: "allowedTools", type: "string[]", desc: "Tool name allowlist" },
+ { name: "disallowedTools", type: "string[]", desc: "Tool name denylist" },
+ { name: "maxTurns", type: "number", desc: "Max agent turns" },
+ { name: "abortController", type: "AbortController", desc: "Cancellation signal" },
+ { name: "constraints", type: "object", desc: "temperature, maxTokens, topP, topK" },
+ { name: "hooks", type: "object", desc: "onSessionStart, preToolUse, postToolFailure, preQuery, postResponse, fileChanged, onError lifecycle hooks" },
+];
+
+const messageTypes = [
+ { type: "delta", desc: "Streaming text/thinking chunk", fields: "deltaType, content" },
+ { type: "assistant", desc: "Complete LLM response", fields: "content, model, usage, stopReason" },
+ { type: "tool_use", desc: "Tool invocation", fields: "toolName, args, toolCallId" },
+ { type: "tool_result", desc: "Tool output", fields: "toolName, content, isError, toolCallId" },
+ { type: "system", desc: "Lifecycle events", fields: "subtype, content, metadata" },
+ { type: "user", desc: "User message (multi-turn)", fields: "content" },
+];
+
+export function GitAgentSDK() {
+ const [activeTab, setActiveTab] = useState("query()");
+ const [copied, setCopied] = useState(false);
+
+ const handleCopy = () => {
+ navigator.clipboard.writeText(codeMap[activeTab]);
+ setCopied(true);
+ setTimeout(() => setCopied(false), 2000);
+ track("gitagent_sdk_code_copied");
+ };
+
+ return (
+
+
+
+ SDK
+
+ Programmatic access to GitAgent via query(),{" "}
+ tool(), and{" "}
+ buildTool().
+
+
+
+ {/* A. Tabbed code display */}
+
+
+ {/* Tab bar */}
+
+
+
+
+
+ {tabs.map((tab) => (
+ setActiveTab(tab)}
+ className={`relative px-3 py-1 text-xs font-body rounded transition-colors ${
+ activeTab === tab
+ ? "text-foreground"
+ : "text-muted-foreground hover:text-foreground/70"
+ }`}
+ >
+ {activeTab === tab && (
+
+ )}
+ {tab}
+
+ ))}
+
+
+ {copied ? : }
+
+
+
+
+ {codeMap[activeTab]}
+
+
+
+
+
+
+ {/* B. QueryOptions */}
+
+
+ QueryOptions
+
+
+ {queryOptions.map((opt, i) => (
+
+
+
+ {opt.name}
+
+
+
{opt.type}
+
{opt.desc}
+
+
+
+ ))}
+
+
+
+ {/* C. Message Types */}
+
+
+ Message Types
+
+
+ {messageTypes.map((m, i) => (
+
+
+
+ {m.type}
+
+
+
{m.desc}
+
{m.fields}
+
+
+
+ ))}
+
+
+
+
+ {/* Cost tracking */}
+
+
+ Cost Tracking
+
+
+
+
+
+ );
+}
diff --git a/src/components/gitAgent/GitAgentSchedules.tsx b/src/components/gitAgent/GitAgentSchedules.tsx
new file mode 100644
index 0000000..f792dd6
--- /dev/null
+++ b/src/components/gitAgent/GitAgentSchedules.tsx
@@ -0,0 +1,125 @@
+import { motion } from "framer-motion";
+import { CodeBlock } from "@/components/gitAgent/CodeBlock";
+
+const repeatScheduleYaml = `# schedules/daily-standup.yaml (repeat)
+id: daily-standup
+prompt: "Summarize git commits from the last 24 hours and list open tasks"
+cron: "0 9 * * 1-5"
+mode: repeat
+enabled: true`;
+
+const onceScheduleYaml = `# schedules/quarterly-review.yaml (one-time)
+id: quarterly-review
+prompt: "Generate Q1 performance report"
+mode: once
+runAt: "2026-04-01T09:00:00Z"
+enabled: true`;
+
+const cronPatterns = [
+ { pattern: "0 9 * * 1-5", desc: "Weekdays at 9 AM" },
+ { pattern: "0 9 * * 1", desc: "Every Monday at 9 AM" },
+ { pattern: "0 9 1 * *", desc: "First of month at 9 AM" },
+ { pattern: "0 9 1 */3 *", desc: "Quarterly" },
+ { pattern: "*/30 * * * *", desc: "Every 30 minutes" },
+ { pattern: "0 0 * * *", desc: "Daily at midnight" },
+];
+
+export function GitAgentSchedules() {
+ return (
+
+
+
+ Schedules
+
+ Automate agent runs on a cron schedule or as one-time tasks.
+
+
+
+ {/* A. Schedule definitions */}
+
+
+ Schedule Definitions
+
+
+
+
+
+
+
+
+ {/* B. Cron Patterns */}
+
+
+ Common Cron Patterns
+
+
+ {cronPatterns.map((row, i) => (
+
+
+
+ {row.pattern}
+
+ |
+ {row.desc}
+
+
+ ))}
+
+
+
+ {/* C. UI Management card */}
+
+
+ Web UI Management
+
+
+
+ The Scheduler tab in the web UI lets you manage schedules without editing YAML files.
+
+
+ {[
+ "Create new schedules with a visual form",
+ "Edit existing schedule prompts and timing",
+ "Enable or disable schedules with a toggle",
+ "Trigger a schedule immediately for testing",
+ "Delete schedules you no longer need",
+ ].map((item, i) => (
+
+ ))}
+
+
+
+
+
+
+ );
+}
diff --git a/src/components/gitAgent/GitAgentSecurity.tsx b/src/components/gitAgent/GitAgentSecurity.tsx
new file mode 100644
index 0000000..928340b
--- /dev/null
+++ b/src/components/gitAgent/GitAgentSecurity.tsx
@@ -0,0 +1,170 @@
+import { motion } from "framer-motion";
+import { Shield } from "lucide-react";
+import { CodeBlock } from "@/components/gitAgent/CodeBlock";
+
+const passwordBashCode = `# Basic auth
+GITAGENT_PASSWORD=mysecret gitagent --voice --dir ~/assistant
+
+# With custom username (defaults to "admin")
+GITAGENT_USERNAME=alice GITAGENT_PASSWORD=mysecret gitagent --voice --dir ~/assistant`;
+
+const sandboxCode = `# Run agent in an E2B cloud sandbox
+gitagent --sandbox --dir ~/assistant
+
+# Clone a remote repo into the sandbox
+gitagent --sandbox --sandbox-repo https://github.com/user/repo --dir ~/assistant`;
+
+const passwordFeatures = [
+ "All HTTP routes show a login page instead of the UI",
+ "WebSocket connections are rejected without valid auth cookie",
+ "/health endpoint remains open (for load balancers)",
+ "Cookie: HttpOnly, SameSite=Strict, 24-hour expiry",
+ "Token is SHA-256 hash (password never stored in cookie)",
+ "GITAGENT_USERNAME sets the login username (defaults to \"admin\")",
+];
+
+const bestPractices = [
+ { title: "Use HTTPS in production", desc: "Via nginx, Caddy, or Cloudflare Tunnel" },
+ { title: "Set GITAGENT_PASSWORD", desc: "When exposing to a network" },
+ { title: "Use --sandbox for untrusted code", desc: "Runs the agent in an isolated E2B cloud VM" },
+ { title: "Enable audit logging", desc: "For compliance and incident review" },
+];
+
+const sandboxPoints = [
+ {
+ title: "Cloud VM isolation",
+ desc: "Agent runs inside an E2B cloud sandbox — fully isolated from your local machine.",
+ },
+ {
+ title: "Filesystem isolation",
+ desc: "The sandbox has its own filesystem. Your host files are not accessible unless explicitly mounted.",
+ },
+ {
+ title: "Remote repo support",
+ desc: "Use --sandbox-repo to clone a repository directly into the sandbox environment.",
+ },
+ {
+ title: "API token required",
+ desc: "Set E2B_API_KEY in your environment — the E2B SDK reads it directly. --sandbox-token is a Git token for cloning the repository (falls back to GITHUB_TOKEN / GIT_TOKEN).",
+ },
+];
+
+export function GitAgentSecurity() {
+ return (
+
+
+
+ Security
+
+ Password protection, best practices, and cloud sandboxing via E2B.
+
+
+
+
+ {/* A. Password Protection */}
+
+
+ Password Protection
+
+
+
+ {passwordFeatures.map((f, i) => (
+
+ —
+ {f}
+
+ ))}
+
+
+
+ {/* B. Best Practices */}
+
+
+ Best Practices
+
+
+ {bestPractices.map((p, i) => (
+
+
+
+ ))}
+
+
+
+
+ {/* C. E2B Sandboxing */}
+
+
+
+
E2B Cloud Sandbox
+
+
+ Run the agent in an isolated E2B cloud VM via the --sandbox flag
+
+
+
+ {sandboxPoints.map((p, i) => (
+
+
+
+ ))}
+
+
+
+ Quick Start
+
+
+
+
+
+ );
+}
diff --git a/src/components/gitAgent/GitAgentSidebar.tsx b/src/components/gitAgent/GitAgentSidebar.tsx
new file mode 100644
index 0000000..dbe1cc0
--- /dev/null
+++ b/src/components/gitAgent/GitAgentSidebar.tsx
@@ -0,0 +1,106 @@
+export const sidebarGroups = [
+ {
+ label: "Getting Started",
+ slug: "getting-started",
+ items: [
+ { id: "overview", label: "Overview" },
+ { id: "quickstart", label: "Quick Start" },
+ { id: "interfaces", label: "Ways to Interact" },
+ { id: "architecture", label: "Architecture" },
+ ],
+ },
+ {
+ label: "Interfaces",
+ slug: "interfaces",
+ items: [
+ { id: "cli", label: "CLI" },
+ { id: "webui", label: "Web & Voice" },
+ { id: "messaging", label: "Messaging" },
+ { id: "sdk", label: "SDK" },
+ ],
+ },
+ {
+ label: "Configuration",
+ slug: "configuration",
+ items: [
+ { id: "models", label: "Models & Providers" },
+ { id: "env", label: "Environment Variables" },
+ ],
+ },
+ {
+ label: "Capabilities",
+ slug: "capabilities",
+ items: [
+ { id: "tools", label: "Tools" },
+ { id: "skills", label: "Skills" },
+ { id: "workflows", label: "Workflows" },
+ { id: "hooks", label: "Hooks" },
+ { id: "plugins", label: "Plugins" },
+ ],
+ },
+ {
+ label: "Data & Integrations",
+ slug: "data",
+ items: [
+ { id: "memory", label: "Memory System" },
+ { id: "schedules", label: "Schedules & Cron" },
+ { id: "integrations", label: "Integrations" },
+ ],
+ },
+ {
+ label: "Enterprise",
+ slug: "enterprise",
+ items: [
+ { id: "compliance", label: "Compliance & Audit" },
+ { id: "security", label: "Security" },
+ ],
+ },
+ {
+ label: "SDK & Utilities",
+ slug: "sdk",
+ items: [
+ { id: "utilities", label: "Utilities" },
+ { id: "telemetry", label: "Telemetry" },
+ ],
+ },
+];
+
+export function GitAgentSidebar({ activeSection }: { activeSection: string }) {
+ return (
+
+
+
+ Contents
+
+
+ {sidebarGroups.map((group, groupIndex) => (
+
+
+ {group.label}
+
+
+ {group.items.map((s) => {
+ const isActive = activeSection === s.id;
+ return (
+
+
+ {s.label}
+
+
+ );
+ })}
+
+
+ ))}
+
+
+
+ );
+}
diff --git a/src/components/gitAgent/GitAgentSkills.tsx b/src/components/gitAgent/GitAgentSkills.tsx
new file mode 100644
index 0000000..3a736c4
--- /dev/null
+++ b/src/components/gitAgent/GitAgentSkills.tsx
@@ -0,0 +1,213 @@
+import { motion } from "framer-motion";
+import { ArrowDown, Folder, FileText } from "lucide-react";
+import { CodeBlock } from "@/components/gitAgent/CodeBlock";
+
+const skillMdExample = `---
+name: code-review
+description: Review code for bugs, style, and security issues
+---
+
+# Code Review
+
+## Instructions
+
+1. Read the specified file(s) using the read tool
+2. Analyze for:
+ - Bugs and logic errors
+ - Security vulnerabilities (OWASP top 10)
+ - Code style and readability
+ - Performance issues
+3. Write a review report to workspace/review.md
+
+## Output Format
+
+For each issue found:
+- **File**: path
+- **Line**: number
+- **Severity**: critical / warning / info
+- **Description**: what's wrong
+- **Fix**: suggested change`;
+
+const invokeExample = `# In REPL
+/skill:code-review Review the auth module
+
+# In voice/text
+"Use the code-review skill on src/auth.ts"
+
+# Via SDK
+query({ prompt: "/skill:code-review Review src/auth.ts", dir: "./my-agent" })`;
+
+const learningSteps = [
+ {
+ num: "01",
+ title: "Task begins",
+ desc: "task_tracker begins tracking a task",
+ },
+ {
+ num: "02",
+ title: "Task completes",
+ desc: "Agent completes the task successfully",
+ },
+ {
+ num: "03",
+ title: "Evaluation",
+ desc: "skill_learner evaluates if the approach is worth saving",
+ },
+ {
+ num: "04",
+ title: "Crystallization",
+ desc: "If the task passes worthiness checks, crystallizes it as a new skill",
+ },
+ {
+ num: "05",
+ title: "Reuse",
+ desc: "Future tasks search for matching skills",
+ },
+ {
+ num: "06",
+ title: "Feedback loop",
+ desc: "Confidence adjusts based on success/failure outcomes",
+ },
+];
+
+export function GitAgentSkills() {
+ return (
+
+
+ {/* Section heading */}
+
+
+ Skills
+
+
+ Skills are reusable task modules defined in Markdown with YAML frontmatter. The agent
+ learns new skills automatically and crystallizes effective patterns.
+
+
+
+ {/* A. SKILL.md format */}
+
+
+ SKILL.md Format
+
+
+ Auto-generated fields added by the skill learner:
+ "\nlearned_at: ""\nusage_count: 0\nsuccess_count: 0\nfailure_count: 0\nnegative_examples: []`}
+ filename="auto-generated frontmatter"
+ />
+
+
+ {/* B. Invoking Skills */}
+
+
+ Invoking Skills
+
+
+
+
+ {/* C. Skill Learning Workflow */}
+
+
+ Skill Learning Workflow
+
+
+ {learningSteps.map((step, i) => (
+
+
+
+
+ {step.num}
+
+
+
+ {step.title}
+
+
+ {step.desc}
+
+
+
+
+ {i < learningSteps.length - 1 && (
+
+ )}
+
+ ))}
+
+
+
+ {/* D. Skill Directory Structure */}
+
+
+ Skill Directory Structure
+
+
+
+ {[
+ { indent: 0, icon: Folder, name: "skills/", type: "dir" },
+ { indent: 1, icon: Folder, name: "code-review/", type: "dir" },
+ { indent: 2, icon: FileText, name: "SKILL.md", type: "file", note: "skill instructions + frontmatter" },
+ { indent: 2, icon: Folder, name: "scripts/", type: "dir" },
+ { indent: 3, icon: FileText, name: "lint.sh", type: "file", note: "helper scripts" },
+ ].map((item) => {
+ const Icon = item.icon;
+ return (
+
+
+ {item.name}
+ {item.note && (
+
+ ← {item.note}
+
+ )}
+
+ );
+ })}
+
+
+
+
+
+ );
+}
diff --git a/src/components/gitAgent/GitAgentTools.tsx b/src/components/gitAgent/GitAgentTools.tsx
new file mode 100644
index 0000000..eff0dad
--- /dev/null
+++ b/src/components/gitAgent/GitAgentTools.tsx
@@ -0,0 +1,241 @@
+import { motion } from "framer-motion";
+import { Terminal, FileText, FilePlus, Brain, Camera, ListChecks, BookOpen } from "lucide-react";
+import { CodeBlock } from "@/components/gitAgent/CodeBlock";
+
+const builtinTools = [
+ {
+ icon: Terminal,
+ name: "cli",
+ desc: "Execute shell commands",
+ concurrent: false,
+ readOnly: false,
+ },
+ {
+ icon: FileText,
+ name: "read",
+ desc: "Read file contents with pagination",
+ concurrent: true,
+ readOnly: true,
+ },
+ {
+ icon: FilePlus,
+ name: "write",
+ desc: "Create/write files (auto-creates dirs)",
+ concurrent: false,
+ readOnly: false,
+ },
+ {
+ icon: FileText,
+ name: "edit",
+ desc: "Edit existing file contents (find and replace)",
+ concurrent: false,
+ readOnly: false,
+ },
+ {
+ icon: Brain,
+ name: "memory",
+ desc: "Load/save git-committed memory (auto-archives)",
+ concurrent: false,
+ readOnly: false,
+ },
+ {
+ icon: Camera,
+ name: "capture_photo",
+ desc: "Capture camera frame as photo",
+ concurrent: false,
+ readOnly: false,
+ },
+ {
+ icon: ListChecks,
+ name: "task_tracker",
+ desc: "Track task progress, search skills",
+ concurrent: false,
+ readOnly: false,
+ },
+ {
+ icon: BookOpen,
+ name: "skill_learner",
+ desc: "Save/evaluate learned skills with confidence",
+ concurrent: false,
+ readOnly: false,
+ },
+];
+
+const toolDetails = [
+ {
+ name: "cli",
+ rows: [
+ { key: "Timeout", value: "120s (configurable)" },
+ { key: "Output", value: "stdout + stderr (truncated to ~100 KB)" },
+ ],
+ },
+ {
+ name: "read",
+ rows: [
+ { key: "Encoding", value: "utf-8 (binary files return a placeholder message)" },
+ { key: "Partial reads", value: "line offsets (offset = start line, limit = number of lines)" },
+ ],
+ },
+ {
+ name: "write",
+ rows: [
+ { key: "Directories", value: "Auto-creates parent directories" },
+ ],
+ },
+ {
+ name: "memory",
+ rows: [
+ { key: "load", value: "Returns MEMORY.md contents" },
+ { key: "save", value: "Appends + git commits" },
+ { key: "Archive", value: "Auto-archives when max_lines exceeded to memory/archive/.md" },
+ ],
+ },
+];
+
+const declarativeYaml = `# tools/lookup-account.yaml
+name: lookup-account
+description: Look up account details by customer ID
+input_schema:
+ properties:
+ customer_id:
+ type: string
+ description: The customer ID
+ required: [customer_id]
+implementation:
+ script: scripts/lookup.sh
+ runtime: sh`;
+
+export function GitAgentTools() {
+ return (
+
+ );
+}
diff --git a/src/components/gitAgent/GitAgentUtilities.tsx b/src/components/gitAgent/GitAgentUtilities.tsx
new file mode 100644
index 0000000..8014909
--- /dev/null
+++ b/src/components/gitAgent/GitAgentUtilities.tsx
@@ -0,0 +1,289 @@
+import { motion } from "framer-motion";
+import { Activity } from "lucide-react";
+import { CodeBlock } from "@/components/gitAgent/CodeBlock";
+
+const compactionCode = `import {
+ estimateTokens,
+ estimateMessageTokens,
+ needsCompaction,
+ truncateToolResults,
+ buildCompactPrompt
+} from "@open-gitagent/gitagent";
+
+// Estimate tokens in a string
+const tokens = estimateTokens("Hello world"); // ~3
+
+// Check if compaction needed (triggers at 75% of context window)
+// tokenEstimate is also returned and useful for logging
+const { needed, ratio, tokenEstimate } = needsCompaction(messages, 200000);
+if (needed) console.log(\`Context at \${(ratio * 100).toFixed(0)}% — compaction needed\`);
+
+// Truncate oversized tool results (keeps first + last half)
+const trimmed = truncateToolResults(messages, 10000);
+
+// Build a summarization prompt for the LLM
+const prompt = buildCompactPrompt(messages);`;
+
+const costTrackingCode = `import { query } from "@open-gitagent/gitagent";
+
+const result = query({ prompt: "...", dir: "..." });
+
+for await (const msg of result) { /* ... */ }
+
+const costs = result.costs();
+// {
+// startTime: 1716825600000,
+// totalCostUsd: 0.05,
+// totalInputTokens: 5000,
+// totalOutputTokens: 2000,
+// totalRequests: 3,
+// modelUsage: {
+// "anthropic:claude-sonnet-4-6": {
+// inputTokens: 5000,
+// outputTokens: 2000,
+// cacheReadTokens: 0,
+// cacheWriteTokens: 0,
+// totalTokens: 7000,
+// requests: 3,
+// costUsd: 0.05
+// }
+// }
+// }
+console.log(\`Session cost: $\${costs.totalCostUsd.toFixed(4)}\`);`;
+
+const compactionUtils = [
+ { name: "estimateTokens", desc: "Fast approximation: chars/4" },
+ { name: "needsCompaction", desc: "Triggers at 75% of model context window" },
+ { name: "truncateToolResults", desc: "Keeps first and last half of large results" },
+ { name: "buildCompactPrompt", desc: "Generates a prompt asking the LLM to summarize the conversation" },
+];
+
+const otelEnvVars = [
+ { key: "OTEL_EXPORTER_OTLP_ENDPOINT", desc: "OTLP/HTTP collector URL (e.g. http://localhost:4318). When set, telemetry is auto-enabled.", default: "unset = off" },
+ { key: "GITAGENT_OTEL_ENABLED", desc: "Set to false to force-disable telemetry even when endpoint is set.", default: "auto" },
+ { key: "OTEL_SERVICE_NAME", desc: "service.name resource attribute.", default: "gitagent" },
+ { key: "OTEL_SERVICE_VERSION", desc: "service.version resource attribute.", default: "unset" },
+ { key: "OTEL_EXPORTER_OTLP_HEADERS", desc: "Comma-separated key=value pairs, no quotes (e.g. Authorization=Bearer xyz,x-tenant=abc).", default: "unset" },
+ { key: "OTEL_TRACES_EXPORTER", desc: "Set to console to print spans to stdout — no collector needed.", default: "unset" },
+];
+
+const otelSpans = [
+ { name: "gitagent.agent.session", kind: "INTERNAL", attrs: "gitagent.entry, gitagent.cost_usd, gitagent.session.duration_ms" },
+ { name: "gitagent.tool.execute", kind: "INTERNAL", attrs: "tool.name, tool.call_id, tool.status, tool.error_message" },
+ { name: "gen_ai.chat", kind: "CLIENT", attrs: "gen_ai.system, gen_ai.request.model, gen_ai.usage.input_tokens, gen_ai.usage.output_tokens, gitagent.cost_usd" },
+ { name: "HTTP …", kind: "CLIENT", attrs: "URL, status code, duration (auto via instrumentation-undici)" },
+];
+
+const otelMetrics = [
+ { name: "gitagent.tool.calls", type: "counter", desc: "Tool executions, labelled by tool.name" },
+ { name: "gitagent.tool.duration_ms", type: "histogram", desc: "Tool execution duration" },
+ { name: "gitagent.session.duration_ms", type: "histogram", desc: "Session duration" },
+ { name: "gitagent.session.cost_usd", type: "counter", desc: "Cumulative session cost in USD" },
+ { name: "gen_ai.client.token.usage", type: "counter", desc: "Token usage by model and token type" },
+ { name: "gen_ai.client.operation.duration", type: "histogram", desc: "LLM call duration" },
+];
+
+const jaegerSnippet = `docker run -d --name jaeger \\
+ -p 16686:16686 -p 4318:4318 \\
+ jaegertracing/all-in-one:latest
+
+OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 gitagent
+# Open http://localhost:16686`;
+
+export function GitAgentUtilities() {
+ return (
+
+
+
+ Utilities
+
+ Context compaction helpers and cost tracking for programmatic use.
+
+
+
+ {/* A. Context Compaction */}
+
+
+ Context Compaction
+
+
+
+ {compactionUtils.map((u, i) => (
+
+
+ {u.name}
+
+ {u.desc}
+
+ ))}
+
+
+
+ {/* B. Cost Tracking */}
+
+
+ Cost Tracking
+
+
+
+
+
+ );
+}
+
+export function GitAgentTelemetry() {
+ return (
+
+
+
+
+
+ Set OTEL_EXPORTER_OTLP_ENDPOINT and telemetry is on. Leave unset for zero overhead.
+
+
+
+
+ {/* Env vars */}
+
+
+ Environment Variables
+
+
+ {otelEnvVars.map((v, i) => (
+
+
+
+ {v.key}
+
+
+
{v.desc}
+
default: {v.default}
+
+
+
+ ))}
+
+
+
+
+ {/* Spans */}
+
+
+ Spans Emitted
+
+
+ {otelSpans.map((s, i) => (
+
+
+
+ {s.name}
+ {s.kind}
+
+
{s.attrs}
+
+
+ ))}
+
+
+
+ {/* Metrics */}
+
+
+ Metrics Emitted
+
+
+ {otelMetrics.map((m, i) => (
+
+
+
+ {m.name}
+ {m.type}
+
+
{m.desc}
+
+
+ ))}
+
+
+
+
+ {/* Jaeger quickstart */}
+
+
+ Jaeger Quickstart
+
+
+
+
+
+
+ );
+}
diff --git a/src/components/gitAgent/GitAgentVoiceSection.tsx b/src/components/gitAgent/GitAgentVoiceSection.tsx
new file mode 100644
index 0000000..5eed9c1
--- /dev/null
+++ b/src/components/gitAgent/GitAgentVoiceSection.tsx
@@ -0,0 +1,119 @@
+import { motion } from "framer-motion";
+import { Mic, Monitor } from "lucide-react";
+
+const voiceAdapters = [
+ {
+ name: "OpenAI Realtime",
+ model: "gpt-realtime-2025-08-28",
+ tag: "default",
+ requires: "OPENAI_API_KEY",
+ },
+ {
+ name: "Gemini Live",
+ model: "gemini-2.0-flash",
+ tag: "free tier",
+ requires: "GEMINI_API_KEY",
+ },
+];
+
+const webUiTabs = [
+ { name: "Chat", desc: "Voice controls, camera, agent vitals, file system viewer" },
+ { name: "Skills", desc: "Browse and install skills from the marketplace" },
+ { name: "Integrations", desc: "Connect Composio services (Gmail, Calendar, Slack, GitHub)" },
+ { name: "Communication", desc: "Telegram bot setup, WhatsApp connection, phone/SMS webhook" },
+ { name: "SkillFlows", desc: "Visual workflow builder — chain skills into multi-step flows" },
+ { name: "Scheduler", desc: "Create cron jobs — run prompts on a recurring schedule" },
+ { name: "Settings", desc: "Model selection, API keys, custom base URL — saves to .env and agent.yaml" },
+];
+
+
+export function GitAgentVoiceSection() {
+ return (
+
+
+
+
+ 04 — Voice & Web UI
+
+
+ Voice Mode & Web UI
+
+
+ Real-time voice, camera, and a full browser interface at{" "}
+ http://localhost:3333
+
+
+
+
+ {/* Left: voice adapters */}
+
+
+ Voice Adapters
+
+
+ {voiceAdapters.map((v, i) => (
+
+
+ {v.name}
+
+ {v.tag}
+
+
+
+
+ Model
+ {v.model}
+
+
+ Requires
+ {v.requires}
+
+
+
+ ))}
+
+
+
+
+ {/* Right: Web UI tabs */}
+
+
+ Web UI Tabs
+
+
+ {webUiTabs.map((tab, i) => (
+
+
+ {tab.name}
+
+
+ {tab.desc}
+
+
+ ))}
+
+
+
+
+
+ );
+}
diff --git a/src/components/gitAgent/GitAgentWebUI.tsx b/src/components/gitAgent/GitAgentWebUI.tsx
new file mode 100644
index 0000000..ead38ac
--- /dev/null
+++ b/src/components/gitAgent/GitAgentWebUI.tsx
@@ -0,0 +1,311 @@
+import { motion } from "framer-motion";
+import {
+ MessageSquare,
+ Zap,
+ Globe,
+ Radio,
+ GitBranch,
+ Clock,
+ Settings,
+ Camera,
+ Mic,
+} from "lucide-react";
+import { CodeBlock } from "@/components/gitAgent/CodeBlock";
+
+const webUITabs = [
+ {
+ icon: MessageSquare,
+ label: "Chat",
+ desc: "Real-time conversation, voice controls, camera, file system viewer",
+ },
+ {
+ icon: Zap,
+ label: "Skills",
+ desc: "Browse and install skills from the marketplace",
+ },
+ {
+ icon: Globe,
+ label: "Integrations",
+ desc: "Connect Composio services (Gmail, Calendar, Slack, GitHub)",
+ },
+ {
+ icon: Radio,
+ label: "Communication",
+ desc: "Telegram bot setup, WhatsApp connection, phone/SMS webhook",
+ },
+ {
+ icon: GitBranch,
+ label: "SkillFlows",
+ desc: "Visual workflow builder — chain skills into multi-step flows",
+ },
+ {
+ icon: Clock,
+ label: "Scheduler",
+ desc: "Create cron jobs — run prompts on a schedule",
+ },
+ {
+ icon: Settings,
+ label: "Settings",
+ desc: "Model selection, API keys, custom base URL — saves to .env and agent.yaml",
+ },
+];
+
+
+const voiceModes = [
+ {
+ provider: "OpenAI Realtime (default)",
+ model: "gpt-realtime-2025-08-28",
+ features: [
+ "Real-time audio streaming over WebSocket",
+ "Supports image input (camera frames)",
+ ],
+ requires: "OPENAI_API_KEY",
+ command: "OPENAI_API_KEY=your_key gitagent --voice --dir ~/assistant",
+ badge: "Default",
+ badgeColor: "bg-primary/15 text-primary",
+ },
+ {
+ provider: "Gemini Live",
+ model: "models/gemini-2.5-flash-native-audio-preview",
+ features: ["Alternative voice provider", "Free tier available"],
+ requires: "GEMINI_API_KEY",
+ command: "GEMINI_API_KEY=your_key gitagent --voice gemini --dir ~/assistant",
+ badge: "Free tier",
+ badgeColor: "bg-green-500/10 text-green-600",
+ },
+];
+
+export function GitAgentWebUI() {
+ return (
+
+
+ {/* Section heading */}
+
+
+ Web UI
+
+
+ A full-featured browser interface served at{" "}
+ http://localhost:3333
+ {" "}— chat, skills, integrations, and voice all in one place.
+
+
+
+ {/* A. Auth / startup */}
+
+
+ Starting the Server
+
+
+
+
+ Auth behaviour
+
+
+ {[
+ "Port is always 3333 — no env var to change it",
+ "All HTTP routes show a login page when GITAGENT_PASSWORD is set",
+ "WebSocket connections are rejected without a valid auth cookie",
+ "/health always stays open (for load balancers)",
+ "Cookie: HttpOnly, SameSite=Strict, 24-hour expiry, SHA-256 token",
+ ].map((item) => (
+
+
+ {item}
+
+ ))}
+
+
+
+
+ {/* B. Web UI Tabs */}
+
+
+ Interface Tabs
+
+
+ {webUITabs.map((tab, i) => {
+ const Icon = tab.icon;
+ return (
+
+
+
+
+ {tab.label}
+
+
+
+ {tab.desc}
+
+
+ );
+ })}
+
+
+
+ {/* C. Voice Mode */}
+
+
+ Voice Mode
+
+
+ {voiceModes.map((mode, i) => (
+
+
+
+
+
+
+ {mode.provider}
+
+
+
+ {mode.badge}
+
+
+
+
+ Model
+
+
+ {mode.model}
+
+
+
+ {mode.features.map((f) => (
+
+
+ {f}
+
+ ))}
+
+
+
+ Requires
+
+
+ {mode.requires}
+
+
+
+
+
+ ))}
+
+
+
+ {/* D. Camera Features + E. Text-Only Fallback — side by side */}
+
+ {/* D. Camera Features */}
+
+
+
+
+
+ Camera Input
+
+
+
+ {[
+ "Front/back camera toggle (mobile)",
+ "Captures frames every 2 seconds as JPEG",
+ "Frames injected into conversation as images",
+ 'Auto-captures on "memorable moments" (laughter, excitement)',
+ ].map((item) => (
+
+
+ {item}
+
+ ))}
+
+
+
+
+ {/* E. Text-Only Fallback */}
+
+
+
+ Text-Only Fallback
+
+
+ No voice API key?
+
+
+ GitAgent still starts the web UI server but with voice disabled. Text input routes
+ directly to the agent via{" "}
+ query().
+
+
+
+ Web UI runs at{" "}
+ http://localhost:3333
+
+
+
+
+
+
+
+ );
+}
diff --git a/src/components/gitAgent/GitAgentWhySection.tsx b/src/components/gitAgent/GitAgentWhySection.tsx
new file mode 100644
index 0000000..8ad36d6
--- /dev/null
+++ b/src/components/gitAgent/GitAgentWhySection.tsx
@@ -0,0 +1,95 @@
+import { motion } from "framer-motion";
+import { GitBranch, Brain, ExternalLink, ShieldCheck } from "lucide-react";
+
+const pillars = [
+ {
+ icon: GitBranch,
+ label: "Full Auditability",
+ desc: "Every agent decision, memory write, and rule change is a git commit. Know exactly what your agent did, when, and why — full audit trail out of the box, no extra tooling needed.",
+ },
+ {
+ icon: ShieldCheck,
+ label: "Compliance & Control",
+ desc: "Human-in-the-loop enforcement, risk tiers, and regulatory support (SOX, GLBA, GDPR, FINRA) baked into the agent manifest. Your compliance team can review the config like any code PR.",
+ },
+ {
+ icon: Brain,
+ label: "Always Learning",
+ desc: "The agent continuously improves from completed tasks, building a library of reusable skills over time. Every learned skill is inspectable, versioned, and reversible — no black-box retraining.",
+ },
+ {
+ icon: ExternalLink,
+ label: "No Vendor Lock-in",
+ desc: "Built on the OpenGAP open standard. Switch between Claude, OpenAI, Gemini, or any provider by changing one line. Your agent definition lives in git — not a vendor's cloud.",
+ link: "/opengap",
+ linkLabel: "About OpenGAP →",
+ },
+];
+
+export function GitAgentWhySection() {
+ return (
+
+
+
+
+ 01 — Why GitAgent
+
+
+ Why GitAgent
+
+
+
+
+
+ Most agent frameworks scatter configuration across your application and lock your agent inside a framework.{" "}
+ GitAgent flips this — your agent IS the git repo.
+
+
+ Identity, memory, rules, tools, and skills are plain files you already know how to manage. Fork it, branch it, diff it, roll it back — everything a developer already does with code, now applied to agents.
+
+
+
+
+ {pillars.map((p, i) => (
+
+
+
+ {p.desc}
+
+ {p.link && (
+
+ {p.linkLabel}
+
+ )}
+
+ ))}
+
+
+
+
+ );
+}
diff --git a/src/components/gitAgent/GitAgentWorkflows.tsx b/src/components/gitAgent/GitAgentWorkflows.tsx
new file mode 100644
index 0000000..faf74ba
--- /dev/null
+++ b/src/components/gitAgent/GitAgentWorkflows.tsx
@@ -0,0 +1,176 @@
+import { motion } from "framer-motion";
+import { ShieldCheck, ArrowRight, Clock, Users, ListOrdered, MessageSquare } from "lucide-react";
+import { CodeBlock } from "@/components/gitAgent/CodeBlock";
+
+const basicWorkflow = `# workflows/cleanup.md
+---
+name: cleanup
+description: Clean up temporary files
+---
+
+# Cleanup Workflow
+Remove temp files and rebuild.`;
+
+const skillFlowYaml = `# workflows/data-pipeline.yaml
+name: data-pipeline
+description: Process data through validation, transformation, and storage
+steps:
+ - skill: validate-input
+ prompt: "Validate the CSV data format"
+
+ - skill: __approval_gate__
+ prompt: "Data validation complete. Approve to continue?"
+ channel: telegram
+
+ - skill: transform-data
+ prompt: "Transform to required schema"
+
+ - skill: save-to-database
+ prompt: "Store results"`;
+
+const skillFlowFeatures = [
+ {
+ icon: ListOrdered,
+ title: "Deterministic Execution",
+ desc: "Skills run in declared order, not LLM discretion",
+ },
+ {
+ icon: ShieldCheck,
+ title: "Approval Gates",
+ desc: "Pause and require human approval via Telegram/WhatsApp",
+ },
+ {
+ icon: ArrowRight,
+ title: "Multi-step",
+ desc: "Chain multiple skills into a single automated pipeline",
+ },
+ {
+ icon: MessageSquare,
+ title: "Prompt Override",
+ desc: "Add per-step instructions with the prompt: field",
+ },
+];
+
+export function GitAgentWorkflows() {
+ return (
+
+
+ {/* Section heading */}
+
+
+ Workflows
+
+
+ Two workflow formats — human-readable Markdown procedures and executable YAML
+ SkillFlows with built-in approval gates.
+
+
+
+ {/* A + B. Basic Workflow + SkillFlow — side by side */}
+
+ {/* A. Basic Workflow */}
+
+
+ Basic Workflow
+
+
+
+ Reference workflow (.md) — human-readable procedure, agent follows as instructions
+
+
+
+ {/* B. SkillFlow */}
+
+
+ SkillFlow (executable YAML)
+
+
+
+ SkillFlow (.yaml) — deterministic, multi-step, executable pipeline
+
+
+
+
+ {/* C. Approval Gates */}
+
+
+
+
+
+ Approval Gates
+
+
+ Steps with{" "}
+ skill: __approval_gate__
+ {" "}pause execution and send an approval request via the specified channel (
+ telegram or{" "}
+ whatsapp). The user has 5
+ minutes to approve or the step times out. Useful for data-modifying operations,
+ deployments, or any critical path requiring human sign-off.{" "}
+ Note: if neither Telegram nor WhatsApp is configured, the gate auto-approves and execution continues.
+
+
+
+
+
+ {/* D. SkillFlow Features */}
+
+
+ SkillFlow Features
+
+
+ {skillFlowFeatures.map((feat, i) => {
+ const Icon = feat.icon;
+ return (
+
+
+
+
+ {feat.title}
+
+
+ {feat.desc}
+
+
+
+ );
+ })}
+
+
+
+
+ );
+}
diff --git a/src/components/opengap/OpenGAPNavbar.tsx b/src/components/opengap/OpenGAPNavbar.tsx
new file mode 100644
index 0000000..af131f4
--- /dev/null
+++ b/src/components/opengap/OpenGAPNavbar.tsx
@@ -0,0 +1,181 @@
+import { useState, useRef, useEffect } from "react";
+import { Menu, X, Search } from "lucide-react";
+import { Sheet, SheetContent, SheetTrigger } from "@/components/ui/sheet";
+import { opengapSidebarGroups } from "@/components/opengap/OpenGAPSidebar";
+
+const allItems = opengapSidebarGroups.flatMap((g) =>
+ g.items.map((item) => ({ ...item, group: g.label, slug: g.slug }))
+);
+
+interface OpenGAPNavbarProps {
+ variant?: "overview" | "docs";
+}
+
+export function OpenGAPNavbar({ variant = "docs" }: OpenGAPNavbarProps) {
+ const [sheetOpen, setSheetOpen] = useState(false);
+ const [query, setQuery] = useState("");
+ const [searchOpen, setSearchOpen] = useState(false);
+ const searchRef = useRef(null);
+
+ useEffect(() => {
+ function handleClickOutside(e: MouseEvent) {
+ if (searchRef.current && !searchRef.current.contains(e.target as Node)) {
+ setSearchOpen(false);
+ }
+ }
+ document.addEventListener("mousedown", handleClickOutside);
+ return () => document.removeEventListener("mousedown", handleClickOutside);
+ }, []);
+
+ const filtered = query
+ ? allItems.filter((item) =>
+ item.label.toLowerCase().includes(query.toLowerCase()) ||
+ item.group.toLowerCase().includes(query.toLowerCase())
+ )
+ : allItems;
+
+ return (
+
+
+ {/* Left: back + Logo */}
+
+
+ {/* Middle: search — docs variant only, desktop */}
+ {variant === "docs" && (
+
+
+
+ setQuery(e.target.value)}
+ onFocus={() => setSearchOpen(true)}
+ placeholder="Search…"
+ className="text-xs font-body bg-transparent outline-none text-foreground placeholder:text-muted-foreground/40 w-full"
+ />
+ {query && (
+ setQuery("")}
+ className="text-muted-foreground/50 hover:text-foreground transition-colors shrink-0"
+ aria-label="Clear search"
+ >
+
+
+ )}
+
+
+ {searchOpen && (
+
+ {filtered.length === 0 ? (
+
No results
+ ) : (
+
+ )}
+
+ )}
+
+ )}
+
+ {/* Right — desktop */}
+
+
+ {/* Mobile right */}
+
+ {variant === "docs" ? (
+
+
+
+ {sheetOpen ? : }
+
+
+
+
+ Open GAP
+
+
+ {opengapSidebarGroups.map((group, groupIndex) => (
+
+ ))}
+
+
+
+
+ ) : (
+
+ GitHub
+
+ )}
+
+
+
+ );
+}
diff --git a/src/components/opengap/OpenGAPSidebar.tsx b/src/components/opengap/OpenGAPSidebar.tsx
new file mode 100644
index 0000000..1ede6ac
--- /dev/null
+++ b/src/components/opengap/OpenGAPSidebar.tsx
@@ -0,0 +1,84 @@
+export const opengapSidebarGroups = [
+ {
+ label: "Getting Started",
+ slug: "getting-started",
+ items: [
+ { id: "overview", label: "Overview" },
+ { id: "quickstart", label: "Quick Start" },
+ ],
+ },
+ {
+ label: "Concepts",
+ slug: "concepts",
+ items: [
+ { id: "why", label: "Why OpenGAP" },
+ { id: "how-it-works", label: "How It Works" },
+ { id: "patterns", label: "Agent Patterns" },
+ ],
+ },
+ {
+ label: "Features",
+ slug: "features",
+ items: [
+ { id: "cli", label: "CLI" },
+ { id: "export", label: "Export" },
+ { id: "adapters", label: "Adapters" },
+ ],
+ },
+ {
+ label: "Skills",
+ slug: "skills",
+ items: [
+ { id: "skills", label: "Skills" },
+ { id: "skillflow", label: "SkillFlow" },
+ ],
+ },
+ {
+ label: "Enterprise",
+ slug: "enterprise",
+ items: [
+ { id: "compliance", label: "Compliance" },
+ { id: "faq", label: "FAQ" },
+ ],
+ },
+];
+
+export function OpenGAPSidebar({ activeSection }: { activeSection: string }) {
+ return (
+
+
+
+ Contents
+
+
+ {opengapSidebarGroups.map((group, groupIndex) => (
+
+
+ {group.label}
+
+
+ {group.items.map((s) => {
+ const isActive = activeSection === s.id;
+ return (
+
+
+ {s.label}
+
+
+ );
+ })}
+
+
+ ))}
+
+
+
+ );
+}
diff --git a/src/index.css b/src/index.css
index 587915d..d9468ee 100644
--- a/src/index.css
+++ b/src/index.css
@@ -117,6 +117,22 @@
opacity: 0.4;
}
+ /* Dark hero override — all CSS-variable-based classes auto-adapt */
+ .hero-dark {
+ background-color: hsl(240 28% 5%);
+ --foreground: 220 15% 92%;
+ --card: 240 22% 9%;
+ --card-foreground: 220 15% 92%;
+ --primary: 258 75% 72%;
+ --primary-foreground: 240 28% 5%;
+ --muted: 240 18% 14%;
+ --muted-foreground: 220 10% 54%;
+ --accent: 240 18% 14%;
+ --accent-foreground: 220 15% 88%;
+ --border: 240 18% 20%;
+ --ring: 258 75% 72%;
+ }
+
/* Sketch border effect */
.sketch-border {
border: 1.5px solid hsl(var(--foreground) / 0.25);
@@ -171,3 +187,4 @@
transform: translateY(-5%) scaleY(1);
}
}
+
diff --git a/src/pages/GitAgentDocsPage.tsx b/src/pages/GitAgentDocsPage.tsx
new file mode 100644
index 0000000..13621a2
--- /dev/null
+++ b/src/pages/GitAgentDocsPage.tsx
@@ -0,0 +1,135 @@
+import { useEffect } from "react";
+import { useParams } from "react-router-dom";
+import { ChevronUp, ChevronLeft, ChevronRight } from "lucide-react";
+import { GitAgentNavbar } from "@/components/gitAgent/GitAgentNavbar";
+import { GitAgentSidebar } from "@/components/gitAgent/GitAgentSidebar";
+import { GitAgentOverview } from "@/components/gitAgent/GitAgentOverview";
+import { GitAgentArchitecture } from "@/components/gitAgent/GitAgentArchitecture";
+import { GitAgentInterfaces } from "@/components/gitAgent/GitAgentInterfaces";
+import { GitAgentMessaging } from "@/components/gitAgent/GitAgentMessaging";
+import { GitAgentQuickStart } from "@/components/gitAgent/GitAgentQuickStart";
+import { GitAgentCLI } from "@/components/gitAgent/GitAgentCLI";
+import { GitAgentModels } from "@/components/gitAgent/GitAgentModels";
+import { GitAgentWebUI } from "@/components/gitAgent/GitAgentWebUI";
+import { GitAgentTools } from "@/components/gitAgent/GitAgentTools";
+import { GitAgentSkills } from "@/components/gitAgent/GitAgentSkills";
+import { GitAgentWorkflows } from "@/components/gitAgent/GitAgentWorkflows";
+import { GitAgentHooks } from "@/components/gitAgent/GitAgentHooks";
+import { GitAgentPlugins } from "@/components/gitAgent/GitAgentPlugins";
+import { GitAgentMemory } from "@/components/gitAgent/GitAgentMemory";
+import { GitAgentSchedules } from "@/components/gitAgent/GitAgentSchedules";
+import { GitAgentIntegrations } from "@/components/gitAgent/GitAgentIntegrations";
+import { GitAgentCompliance } from "@/components/gitAgent/GitAgentCompliance";
+import { GitAgentSDK } from "@/components/gitAgent/GitAgentSDK";
+import { GitAgentUtilities, GitAgentTelemetry } from "@/components/gitAgent/GitAgentUtilities";
+import { GitAgentSecurity } from "@/components/gitAgent/GitAgentSecurity";
+import { GitAgentEnvVars } from "@/components/gitAgent/GitAgentEnvVars";
+import { sidebarGroups } from "@/components/gitAgent/GitAgentSidebar";
+import { Footer } from "@/components/Footer";
+import { useState } from "react";
+
+const SECTION_COMPONENTS: Record = {
+ overview: GitAgentOverview,
+ quickstart: GitAgentQuickStart,
+ interfaces: GitAgentInterfaces,
+ architecture: GitAgentArchitecture,
+ cli: GitAgentCLI,
+ models: GitAgentModels,
+ env: GitAgentEnvVars,
+ webui: GitAgentWebUI,
+ messaging: GitAgentMessaging,
+ tools: GitAgentTools,
+ skills: GitAgentSkills,
+ workflows: GitAgentWorkflows,
+ hooks: GitAgentHooks,
+ plugins: GitAgentPlugins,
+ memory: GitAgentMemory,
+ schedules: GitAgentSchedules,
+ integrations: GitAgentIntegrations,
+ compliance: GitAgentCompliance,
+ security: GitAgentSecurity,
+ sdk: GitAgentSDK,
+ utilities: GitAgentUtilities,
+ telemetry: GitAgentTelemetry,
+};
+
+const ALL_ITEMS = sidebarGroups.flatMap((g) => g.items);
+
+const GitAgentDocsPage = () => {
+ const { section = "overview" } = useParams<{ section: string }>();
+ const [showBackToTop, setShowBackToTop] = useState(false);
+
+ const currentIndex = ALL_ITEMS.findIndex((item) => item.id === section);
+ const prevItem = currentIndex > 0 ? ALL_ITEMS[currentIndex - 1] : null;
+ const nextItem = currentIndex < ALL_ITEMS.length - 1 ? ALL_ITEMS[currentIndex + 1] : null;
+
+ const SectionComponent = SECTION_COMPONENTS[section] ?? GitAgentOverview;
+ const currentLabel = ALL_ITEMS.find((item) => item.id === section)?.label ?? "Docs";
+
+ useEffect(() => {
+ document.title = `GitAgent Docs — ${currentLabel}`;
+ window.scrollTo(0, 0);
+ }, [section, currentLabel]);
+
+ useEffect(() => {
+ const handleScroll = () => setShowBackToTop(window.scrollY > 400);
+ window.addEventListener("scroll", handleScroll, { passive: true });
+ return () => window.removeEventListener("scroll", handleScroll);
+ }, []);
+
+ return (
+
+
+
+
+
+
+
+
+
+ {/* Prev / Next navigation */}
+
+
+
+
+
+
+ {showBackToTop && (
+
window.scrollTo({ top: 0, behavior: "smooth" })}
+ className="fixed bottom-6 right-6 z-50 p-2 rounded-md sketch-border bg-background text-muted-foreground hover:text-foreground transition-colors"
+ aria-label="Back to top"
+ >
+
+
+ )}
+
+ );
+};
+
+export default GitAgentDocsPage;
diff --git a/src/pages/GitAgentPage.tsx b/src/pages/GitAgentPage.tsx
new file mode 100644
index 0000000..039b53a
--- /dev/null
+++ b/src/pages/GitAgentPage.tsx
@@ -0,0 +1,118 @@
+import { useEffect, useState } from "react";
+import { ChevronUp } from "lucide-react";
+import { GitAgentNavbar } from "@/components/gitAgent/GitAgentNavbar";
+import { GitAgentHeroSection } from "@/components/gitAgent/GitAgentHeroSection";
+import { GitAgentWhySection } from "@/components/gitAgent/GitAgentWhySection";
+import { GitAgentArchitectureSection } from "@/components/gitAgent/GitAgentArchitectureSection";
+import { GitAgentInterfaces } from "@/components/gitAgent/GitAgentInterfaces";
+import { GitAgentFeaturesSection } from "@/components/gitAgent/GitAgentFeaturesSection";
+import { GitAgentModelsSection } from "@/components/gitAgent/GitAgentModelsSection";
+import { GitAgentMemorySection } from "@/components/gitAgent/GitAgentMemorySection";
+import { GitAgentIntegrationsSection } from "@/components/gitAgent/GitAgentIntegrationsSection";
+import { GitAgentInstallSection } from "@/components/gitAgent/GitAgentInstallSection";
+import { Footer } from "@/components/Footer";
+
+const overviewSections = [
+ { id: "why-gitagent", label: "Why" },
+ { id: "interfaces", label: "Interfaces" },
+ { id: "architecture", label: "Architecture" },
+ { id: "features", label: "Features" },
+ { id: "models", label: "Models" },
+ { id: "memory", label: "Memory" },
+ { id: "integrations", label: "Integrations" },
+ { id: "install", label: "Install" },
+];
+
+const GitAgentPage = () => {
+ const [activeSection, setActiveSection] = useState("");
+ const [showPageNav, setShowPageNav] = useState(false);
+ const [showBackToTop, setShowBackToTop] = useState(false);
+
+ useEffect(() => {
+ document.title = "GitAgent — Git-Native AI Agent";
+ }, []);
+
+ useEffect(() => {
+ const handleScroll = () => {
+ const scrollY = window.scrollY;
+ setShowPageNav(scrollY > 300);
+ setShowBackToTop(scrollY > 400);
+ };
+ window.addEventListener("scroll", handleScroll, { passive: true });
+ return () => window.removeEventListener("scroll", handleScroll);
+ }, []);
+
+ useEffect(() => {
+ const observers: IntersectionObserver[] = [];
+ overviewSections.forEach(({ id }) => {
+ const el = document.getElementById(id);
+ if (!el) return;
+ const observer = new IntersectionObserver(
+ ([entry]) => {
+ if (entry.isIntersecting) setActiveSection(id);
+ },
+ { rootMargin: "-20% 0px -70% 0px", threshold: 0 }
+ );
+ observer.observe(el);
+ observers.push(observer);
+ });
+ return () => observers.forEach((o) => o.disconnect());
+ }, []);
+
+ return (
+
+
+
+
+ {/* Sticky secondary page-nav */}
+ {showPageNav && (
+
+
+
+ {overviewSections.map(({ id, label }) => (
+
+ {label}
+
+ ))}
+
+
+
+ )}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* Back to top */}
+ {showBackToTop && (
+
window.scrollTo({ top: 0, behavior: "smooth" })}
+ className="fixed bottom-6 right-6 z-50 p-2 rounded-md sketch-border bg-background text-muted-foreground hover:text-foreground transition-colors"
+ aria-label="Back to top"
+ >
+
+
+ )}
+
+ );
+};
+
+export default GitAgentPage;
diff --git a/src/pages/Index.tsx b/src/pages/Index.tsx
index c7bc4b1..4a93a14 100644
--- a/src/pages/Index.tsx
+++ b/src/pages/Index.tsx
@@ -1,4 +1,4 @@
-import { Navbar } from "@/components/Navbar";
+import { GitAgentNavbar } from "@/components/gitAgent/GitAgentNavbar";
import { HeroSection } from "@/components/HeroSection";
import { WhySection } from "@/components/WhySection";
import { PatternsSection } from "@/components/PatternsSection";
@@ -34,7 +34,7 @@ const Index = () => {
return (
-
+
{/* spacer for fixed announcement strip */}
;
+import { QuickStartSection } from "@/components/QuickStartSection";
+import { WhySection } from "@/components/WhySection";
+import { HowItWorksSection } from "@/components/HowItWorksSection";
+import { PatternsSection } from "@/components/PatternsSection";
+import { CLISection } from "@/components/CLISection";
+import { ExportSection } from "@/components/ExportSection";
+import { AdaptersSection } from "@/components/AdaptersSection";
+import { SkillsSection } from "@/components/SkillsSection";
+import { SkillsFlowSection } from "@/components/SkillsFlowSection";
+import { ComplianceSection } from "@/components/ComplianceSection";
+import { FAQSection } from "@/components/FAQSection";
+import { Footer } from "@/components/Footer";
+
+const SECTION_COMPONENTS: Record = {
+ overview: HeroSectionDocs,
+ quickstart: QuickStartSection,
+ why: WhySection,
+ "how-it-works": HowItWorksSection,
+ patterns: PatternsSection,
+ cli: CLISection,
+ export: ExportSection,
+ adapters: AdaptersSection,
+ skills: SkillsSection,
+ skillflow: SkillsFlowSection,
+ compliance: ComplianceSection,
+ faq: FAQSection,
+};
+
+const ALL_ITEMS = opengapSidebarGroups.flatMap((g) => g.items);
+
+const OpenGAPDocsPage = () => {
+ const { section = "overview" } = useParams<{ section: string }>();
+ const [showBackToTop, setShowBackToTop] = useState(false);
+
+ const currentIndex = ALL_ITEMS.findIndex((item) => item.id === section);
+ const prevItem = currentIndex > 0 ? ALL_ITEMS[currentIndex - 1] : null;
+ const nextItem = currentIndex < ALL_ITEMS.length - 1 ? ALL_ITEMS[currentIndex + 1] : null;
+
+ const SectionComponent = SECTION_COMPONENTS[section] ?? HeroSection;
+ const currentLabel = ALL_ITEMS.find((item) => item.id === section)?.label ?? "Overview";
+
+ useEffect(() => {
+ document.title = `OpenGAP — ${currentLabel}`;
+ window.scrollTo(0, 0);
+ }, [section, currentLabel]);
+
+ useEffect(() => {
+ const handleScroll = () => setShowBackToTop(window.scrollY > 400);
+ window.addEventListener("scroll", handleScroll, { passive: true });
+ return () => window.removeEventListener("scroll", handleScroll);
+ }, []);
+
+ return (
+
+
+
+
+
+
+
+ {showBackToTop && (
+
window.scrollTo({ top: 0, behavior: "smooth" })}
+ className="fixed bottom-6 right-6 z-50 p-2 rounded-md sketch-border bg-background text-muted-foreground hover:text-foreground transition-colors"
+ aria-label="Back to top"
+ >
+
+
+ )}
+
+ );
+};
+
+export default OpenGAPDocsPage;