add documentation

This commit is contained in:
Auto
2026-02-01 17:34:07 +02:00
parent 016eead8b4
commit b2ab1ecc7a
23 changed files with 3290 additions and 37 deletions

View File

@@ -28,7 +28,7 @@ import { ThemeSelector } from './components/ThemeSelector'
import { ResetProjectModal } from './components/ResetProjectModal'
import { ProjectSetupRequired } from './components/ProjectSetupRequired'
import { getDependencyGraph, startAgent } from './lib/api'
import { Loader2, Settings, Moon, Sun, RotateCcw } from 'lucide-react'
import { Loader2, Settings, Moon, Sun, RotateCcw, BookOpen } from 'lucide-react'
import type { Feature } from './lib/types'
import { Button } from '@/components/ui/button'
import { Card, CardContent } from '@/components/ui/card'
@@ -335,6 +335,17 @@ function App() {
</>
)}
{/* Docs link */}
<Button
onClick={() => { window.location.hash = '#/docs' }}
variant="outline"
size="sm"
title="Documentation"
aria-label="Open Documentation"
>
<BookOpen size={18} />
</Button>
{/* Theme selector */}
<ThemeSelector
themes={themes}

View File

@@ -0,0 +1,130 @@
/**
* DocsContent Component
*
* Renders all 13 documentation section components in order.
* Uses IntersectionObserver to detect which section heading is currently
* visible in the viewport, and notifies the parent so the sidebar
* can highlight the active section.
*/
import { useEffect, useRef, useCallback } from 'react'
import { DOC_SECTIONS } from './docsData'
// Section components -- lazy-load candidates in the future, but imported
// statically for now to keep the build simple and deterministic.
import { GettingStarted } from './sections/GettingStarted'
import { AppSpecSetup } from './sections/AppSpecSetup'
import { ProjectStructure } from './sections/ProjectStructure'
import { FeaturesKanban } from './sections/FeaturesKanban'
import { AgentSystem } from './sections/AgentSystem'
import { SettingsConfig } from './sections/SettingsConfig'
import { DeveloperTools } from './sections/DeveloperTools'
import { AIAssistant } from './sections/AIAssistant'
import { Scheduling } from './sections/Scheduling'
import { AppearanceThemes } from './sections/AppearanceThemes'
import { Security } from './sections/Security'
import { AdvancedConfig } from './sections/AdvancedConfig'
import { FAQ } from './sections/FAQ'
interface DocsContentProps {
activeSectionId: string | null
onSectionVisible: (id: string) => void
}
/**
* Maps each section id from docsData to its corresponding React component.
* Order matches DOC_SECTIONS so we can iterate safely.
*/
const SECTION_COMPONENTS: Record<string, React.FC> = {
'getting-started': GettingStarted,
'app-spec-setup': AppSpecSetup,
'project-structure': ProjectStructure,
'features-kanban': FeaturesKanban,
'agent-system': AgentSystem,
'settings-config': SettingsConfig,
'developer-tools': DeveloperTools,
'ai-assistant': AIAssistant,
scheduling: Scheduling,
'appearance-themes': AppearanceThemes,
security: Security,
'advanced-config': AdvancedConfig,
faq: FAQ,
}
export function DocsContent({ onSectionVisible }: DocsContentProps) {
const containerRef = useRef<HTMLDivElement>(null)
// Store refs to each section heading element so the observer can watch them
const headingRefs = useRef<Map<string, HTMLElement>>(new Map())
// Stable callback ref setter -- avoids recreating refs on every render
const setHeadingRef = useCallback((id: string, element: HTMLElement | null) => {
if (element) {
headingRefs.current.set(id, element)
} else {
headingRefs.current.delete(id)
}
}, [])
// IntersectionObserver: track which section heading is at or near the top of the viewport
useEffect(() => {
const headings = headingRefs.current
if (headings.size === 0) return
// rootMargin: trigger when a heading enters the top 20% of the viewport.
// This ensures the sidebar updates *before* the user scrolls past the heading.
const observer = new IntersectionObserver(
(entries) => {
// Find the topmost visible heading -- the one closest to the top of the viewport
const visible = entries
.filter((entry) => entry.isIntersecting)
.sort((a, b) => a.boundingClientRect.top - b.boundingClientRect.top)
if (visible.length > 0) {
const topEntry = visible[0]
const sectionId = topEntry.target.getAttribute('data-section-id')
if (sectionId) {
onSectionVisible(sectionId)
}
}
},
{
// Observe from the very top of the viewport down to -60% from the bottom,
// so headings are detected while in the upper portion of the screen.
rootMargin: '0px 0px -60% 0px',
threshold: 0,
},
)
headings.forEach((element) => observer.observe(element))
return () => observer.disconnect()
}, [onSectionVisible])
return (
<div ref={containerRef} className="docs-prose">
{DOC_SECTIONS.map((section) => {
const SectionComponent = SECTION_COMPONENTS[section.id]
if (!SectionComponent) return null
const Icon = section.icon
return (
<div key={section.id} id={section.id} className="scroll-mt-24 mb-16">
{/* Section heading with anchor */}
<h2
ref={(el) => setHeadingRef(section.id, el)}
data-section-id={section.id}
className="font-display text-2xl font-bold tracking-tight mb-6 flex items-center gap-3
text-foreground border-b-2 border-border pb-3"
>
<Icon size={24} className="text-primary shrink-0" />
{section.title}
</h2>
{/* Section body */}
<SectionComponent />
</div>
)
})}
</div>
)
}

View File

@@ -0,0 +1,215 @@
/**
* DocsPage Component
*
* Main layout for the documentation route (#/docs).
* Full-page layout with a sticky header, collapsible sidebar on the left,
* and scrollable content area on the right.
*
* Mobile-responsive: sidebar collapses behind a hamburger menu that
* opens as an overlay.
*/
import { useState, useEffect, useCallback } from 'react'
import { ArrowLeft, Menu, X, Moon, Sun } from 'lucide-react'
import { useHashRoute } from '../../hooks/useHashRoute'
import { useTheme } from '../../hooks/useTheme'
import { ThemeSelector } from '../ThemeSelector'
import { Button } from '@/components/ui/button'
import { Badge } from '@/components/ui/badge'
import { DocsSidebar } from './DocsSidebar'
import { DocsSearch } from './DocsSearch'
import { DocsContent } from './DocsContent'
export function DocsPage() {
const [activeSectionId, setActiveSectionId] = useState<string | null>(null)
const [searchQuery, setSearchQuery] = useState('')
const [mobileSidebarOpen, setMobileSidebarOpen] = useState(false)
const { section: initialSection } = useHashRoute()
const { theme, setTheme, darkMode, toggleDarkMode, themes } = useTheme()
// On mount, if the hash includes a section id (e.g. #/docs/getting-started),
// scroll to it and set it as active
useEffect(() => {
if (initialSection) {
setActiveSectionId(initialSection)
// Delay scroll slightly so the DOM is rendered
requestAnimationFrame(() => {
const element = document.getElementById(initialSection)
if (element) {
element.scrollIntoView({ behavior: 'smooth', block: 'start' })
}
})
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []) // Run only on mount
// When a sidebar item is clicked, scroll the corresponding element into view
const handleSectionClick = useCallback((id: string) => {
setActiveSectionId(id)
// Update hash for linkability (without triggering a route change)
history.replaceState(null, '', `#/docs/${id}`)
const element = document.getElementById(id)
if (element) {
element.scrollIntoView({ behavior: 'smooth', block: 'start' })
}
}, [])
// Called by DocsContent's IntersectionObserver when a heading scrolls into view
const handleSectionVisible = useCallback((id: string) => {
setActiveSectionId(id)
}, [])
// Close mobile sidebar when pressing Escape
useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => {
if (e.key === 'Escape' && mobileSidebarOpen) {
setMobileSidebarOpen(false)
}
}
window.addEventListener('keydown', handleKeyDown)
return () => window.removeEventListener('keydown', handleKeyDown)
}, [mobileSidebarOpen])
// Prevent body scroll when mobile sidebar overlay is open
useEffect(() => {
if (mobileSidebarOpen) {
document.body.style.overflow = 'hidden'
} else {
document.body.style.overflow = ''
}
return () => {
document.body.style.overflow = ''
}
}, [mobileSidebarOpen])
return (
<div className="min-h-screen bg-background">
{/* Sticky header */}
<header className="sticky top-0 z-50 bg-card/80 backdrop-blur-md text-foreground border-b-2 border-border">
<div className="max-w-7xl mx-auto px-4 py-3">
<div className="flex items-center justify-between">
{/* Left side: hamburger (mobile) + title + badge */}
<div className="flex items-center gap-3">
{/* Mobile hamburger button -- only visible below lg breakpoint */}
<Button
variant="ghost"
size="icon-sm"
className="lg:hidden"
onClick={() => setMobileSidebarOpen(!mobileSidebarOpen)}
aria-label={mobileSidebarOpen ? 'Close sidebar' : 'Open sidebar'}
>
{mobileSidebarOpen ? <X size={20} /> : <Menu size={20} />}
</Button>
<a
href="#/"
className="font-display text-xl font-bold tracking-tight uppercase text-foreground
hover:text-primary transition-colors"
>
AutoCoder
</a>
<Badge variant="secondary" className="text-xs font-medium">
Documentation
</Badge>
</div>
{/* Right side: theme controls + back button */}
<div className="flex items-center gap-2">
<ThemeSelector
themes={themes}
currentTheme={theme}
onThemeChange={setTheme}
/>
<Button
onClick={toggleDarkMode}
variant="outline"
size="sm"
title="Toggle dark mode"
aria-label="Toggle dark mode"
>
{darkMode ? <Sun size={18} /> : <Moon size={18} />}
</Button>
<Button
variant="outline"
size="sm"
asChild
>
<a href="#/" className="inline-flex items-center gap-1.5">
<ArrowLeft size={16} />
<span className="hidden sm:inline">Back to App</span>
</a>
</Button>
</div>
</div>
</div>
</header>
{/* Body: sidebar + content */}
<div className="max-w-7xl mx-auto flex">
{/* ----------------------------------------------------------------
Desktop sidebar -- visible at lg and above
Fixed width, sticky below the header, independently scrollable
---------------------------------------------------------------- */}
<aside
className="hidden lg:block w-[280px] shrink-0 sticky top-[57px] h-[calc(100vh-57px)]
overflow-y-auto border-r border-border p-4 space-y-4"
>
<DocsSearch value={searchQuery} onChange={setSearchQuery} />
<DocsSidebar
activeSectionId={activeSectionId}
onSectionClick={handleSectionClick}
searchQuery={searchQuery}
/>
</aside>
{/* ----------------------------------------------------------------
Mobile sidebar overlay -- visible below lg breakpoint
---------------------------------------------------------------- */}
{mobileSidebarOpen && (
<>
{/* Backdrop */}
<div
className="fixed inset-0 z-40 bg-background/60 backdrop-blur-sm lg:hidden"
onClick={() => setMobileSidebarOpen(false)}
aria-hidden="true"
/>
{/* Sidebar panel */}
<aside
className="fixed top-[57px] left-0 z-50 w-[280px] h-[calc(100vh-57px)]
overflow-y-auto bg-card border-r-2 border-border p-4 space-y-4
animate-slide-in lg:hidden"
>
<DocsSearch value={searchQuery} onChange={setSearchQuery} />
<DocsSidebar
activeSectionId={activeSectionId}
onSectionClick={handleSectionClick}
searchQuery={searchQuery}
onMobileClose={() => setMobileSidebarOpen(false)}
/>
</aside>
</>
)}
{/* ----------------------------------------------------------------
Content area -- fills remaining space, scrollable
---------------------------------------------------------------- */}
<main className="flex-1 min-w-0 px-6 py-8 lg:px-10">
<div className="max-w-[65ch] mx-auto">
<DocsContent
activeSectionId={activeSectionId}
onSectionVisible={handleSectionVisible}
/>
</div>
</main>
</div>
</div>
)
}

View File

@@ -0,0 +1,78 @@
/**
* DocsSearch Component
*
* Search input for the documentation sidebar.
* Supports Ctrl/Cmd+K keyboard shortcut to focus,
* and shows a keyboard hint when the input is empty.
*/
import { useRef, useEffect } from 'react'
import { Search, X } from 'lucide-react'
interface DocsSearchProps {
value: string
onChange: (value: string) => void
}
export function DocsSearch({ value, onChange }: DocsSearchProps) {
const inputRef = useRef<HTMLInputElement>(null)
// Global keyboard shortcut: Ctrl/Cmd+K focuses the search input
useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => {
if ((e.ctrlKey || e.metaKey) && e.key === 'k') {
e.preventDefault()
inputRef.current?.focus()
}
}
window.addEventListener('keydown', handleKeyDown)
return () => window.removeEventListener('keydown', handleKeyDown)
}, [])
return (
<div className="relative">
{/* Search icon */}
<Search
size={16}
className="absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground pointer-events-none"
/>
<input
ref={inputRef}
type="text"
value={value}
onChange={(e) => onChange(e.target.value)}
placeholder="Search docs..."
className="w-full pl-9 pr-16 py-2 text-sm bg-muted border border-border rounded-lg
text-foreground placeholder:text-muted-foreground
focus:outline-none focus:ring-2 focus:ring-ring/50 focus:border-ring
transition-colors"
/>
{/* Right side: clear button when has value, otherwise Ctrl+K hint */}
{value ? (
<button
onClick={() => {
onChange('')
inputRef.current?.focus()
}}
className="absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground
hover:text-foreground transition-colors"
aria-label="Clear search"
>
<X size={16} />
</button>
) : (
<kbd
className="absolute right-3 top-1/2 -translate-y-1/2
text-[10px] text-muted-foreground bg-background
border border-border rounded px-1.5 py-0.5
pointer-events-none select-none"
>
Ctrl+K
</kbd>
)}
</div>
)
}

View File

@@ -0,0 +1,189 @@
/**
* DocsSidebar Component
*
* Left sidebar navigation for the documentation page.
* Lists all sections from docsData with expandable subsections.
* Supports search filtering with auto-expansion of matching sections.
*/
import { useState, useMemo } from 'react'
import { ChevronRight } from 'lucide-react'
import { DOC_SECTIONS, type DocSection } from './docsData'
interface DocsSidebarProps {
activeSectionId: string | null
onSectionClick: (id: string) => void
searchQuery: string
onMobileClose?: () => void
}
export function DocsSidebar({
activeSectionId,
onSectionClick,
searchQuery,
onMobileClose,
}: DocsSidebarProps) {
// Track which top-level sections are manually expanded by the user
const [expandedSections, setExpandedSections] = useState<Set<string>>(() => {
// Start with the first section expanded so the sidebar is not fully collapsed
const initial = new Set<string>()
if (DOC_SECTIONS.length > 0) {
initial.add(DOC_SECTIONS[0].id)
}
return initial
})
const normalizedQuery = searchQuery.trim().toLowerCase()
// Filter sections based on search query, matching against section title,
// subsection titles, and keywords
const filteredSections = useMemo(() => {
if (!normalizedQuery) {
return DOC_SECTIONS
}
return DOC_SECTIONS.filter((section) => {
// Check section title
if (section.title.toLowerCase().includes(normalizedQuery)) return true
// Check keywords
if (section.keywords.some((kw) => kw.toLowerCase().includes(normalizedQuery))) return true
// Check subsection titles
if (section.subsections.some((sub) => sub.title.toLowerCase().includes(normalizedQuery))) {
return true
}
return false
})
}, [normalizedQuery])
// Determine which sections should appear expanded:
// - When searching: auto-expand all matching sections
// - Otherwise: use manual expanded state, plus expand whichever section contains the active item
const isSectionExpanded = (sectionId: string): boolean => {
if (normalizedQuery) return true
if (expandedSections.has(sectionId)) return true
// Also expand the section that contains the currently active subsection
if (activeSectionId) {
const section = DOC_SECTIONS.find((s) => s.id === sectionId)
if (section) {
if (section.id === activeSectionId) return true
if (section.subsections.some((sub) => sub.id === activeSectionId)) return true
}
}
return false
}
const toggleSection = (sectionId: string) => {
setExpandedSections((prev) => {
const next = new Set(prev)
if (next.has(sectionId)) {
next.delete(sectionId)
} else {
next.add(sectionId)
}
return next
})
}
/**
* Checks whether a given id (section or subsection) is the currently active item.
* Active items get a highlighted visual treatment.
*/
const isActive = (id: string): boolean => activeSectionId === id
/**
* Checks whether a section contains the active subsection.
* Used to highlight parent sections in a muted way.
*/
const sectionContainsActive = (section: DocSection): boolean => {
if (!activeSectionId) return false
return section.subsections.some((sub) => sub.id === activeSectionId)
}
const handleItemClick = (id: string) => {
onSectionClick(id)
// On mobile, close the sidebar after navigation
onMobileClose?.()
}
return (
<nav aria-label="Documentation navigation" className="space-y-1">
{filteredSections.map((section) => {
const Icon = section.icon
const expanded = isSectionExpanded(section.id)
const active = isActive(section.id)
const containsActive = sectionContainsActive(section)
return (
<div key={section.id}>
{/* Section header (clickable to expand/collapse and navigate) */}
<button
onClick={() => {
toggleSection(section.id)
handleItemClick(section.id)
}}
className={`w-full flex items-center gap-2 px-3 py-2 text-sm rounded-md
transition-colors cursor-pointer group
${active
? 'bg-primary/10 border-l-2 border-primary text-foreground font-semibold'
: containsActive
? 'text-foreground font-medium'
: 'text-muted-foreground hover:text-foreground hover:bg-muted'
}`}
aria-expanded={expanded}
>
<Icon
size={16}
className={`shrink-0 ${active ? 'text-primary' : 'text-muted-foreground group-hover:text-foreground'}`}
/>
<span className="flex-1 text-left truncate">{section.title}</span>
<ChevronRight
size={14}
className={`shrink-0 text-muted-foreground transition-transform duration-200
${expanded ? 'rotate-90' : ''}`}
/>
</button>
{/* Subsections (shown when expanded) */}
{expanded && (
<div className="ml-4 mt-0.5 space-y-0.5 border-l border-border animate-slide-in-down">
{section.subsections.map((sub) => {
const subActive = isActive(sub.id)
return (
<button
key={sub.id}
onClick={() => handleItemClick(sub.id)}
className={`w-full text-left px-3 py-1.5 text-sm rounded-r-md
transition-colors cursor-pointer
${subActive
? 'bg-primary/10 border-l-2 border-primary text-foreground font-medium -ml-px'
: 'text-muted-foreground hover:text-foreground hover:bg-muted'
}`}
>
{sub.title}
</button>
)
})}
</div>
)}
</div>
)
})}
{/* No results message when search filters everything out */}
{normalizedQuery && filteredSections.length === 0 && (
<div className="px-3 py-6 text-center text-sm text-muted-foreground">
No sections match &ldquo;{searchQuery}&rdquo;
</div>
)}
</nav>
)
}

View File

@@ -0,0 +1,222 @@
import {
Rocket,
FileText,
FolderTree,
LayoutGrid,
Bot,
Settings,
Terminal,
MessageSquare,
Clock,
Palette,
Shield,
Wrench,
HelpCircle,
type LucideIcon,
} from 'lucide-react'
export interface DocSubsection {
id: string
title: string
}
export interface DocSection {
id: string
title: string
icon: LucideIcon
subsections: DocSubsection[]
keywords: string[]
}
export const DOC_SECTIONS: DocSection[] = [
{
id: 'getting-started',
title: 'Getting Started',
icon: Rocket,
subsections: [
{ id: 'what-is-autocoder', title: 'What is AutoCoder?' },
{ id: 'quick-start', title: 'Quick Start' },
{ id: 'creating-a-project', title: 'Creating a New Project' },
{ id: 'existing-project', title: 'Adding to an Existing Project' },
{ id: 'system-requirements', title: 'System Requirements' },
],
keywords: ['install', 'setup', 'start', 'begin', 'new', 'requirements', 'prerequisites'],
},
{
id: 'app-spec-setup',
title: 'App Spec & Project Setup',
icon: FileText,
subsections: [
{ id: 'what-is-app-spec', title: 'What is an App Spec?' },
{ id: 'creating-spec-with-claude', title: 'Creating a Spec with Claude' },
{ id: 'writing-spec-manually', title: 'Writing a Spec Manually' },
{ id: 'initializer-agent', title: 'The Initializer Agent' },
{ id: 'starting-after-spec', title: 'Starting After Spec Creation' },
],
keywords: ['spec', 'specification', 'xml', 'app_spec', 'initializer', 'prompt', 'template'],
},
{
id: 'project-structure',
title: 'Target Project Structure',
icon: FolderTree,
subsections: [
{ id: 'autocoder-directory', title: '.autocoder/ Directory Layout' },
{ id: 'features-db', title: 'Features Database' },
{ id: 'prompts-directory', title: 'Prompts Directory' },
{ id: 'allowed-commands-yaml', title: 'Allowed Commands Config' },
{ id: 'claude-md', title: 'CLAUDE.md Convention' },
{ id: 'legacy-migration', title: 'Legacy Layout Migration' },
{ id: 'claude-inheritance', title: 'Claude Inheritance' },
],
keywords: ['folder', 'directory', 'structure', 'layout', 'files', 'database', 'sqlite', 'migration'],
},
{
id: 'features-kanban',
title: 'Features & Kanban Board',
icon: LayoutGrid,
subsections: [
{ id: 'kanban-overview', title: 'Kanban Board Overview' },
{ id: 'feature-cards', title: 'Feature Cards' },
{ id: 'dependency-graph', title: 'Dependency Graph View' },
{ id: 'adding-features', title: 'Adding Features' },
{ id: 'editing-features', title: 'Editing & Deleting Features' },
{ id: 'feature-dependencies', title: 'Feature Dependencies' },
{ id: 'expanding-with-ai', title: 'Expanding Project with AI' },
{ id: 'feature-priority', title: 'Priority & Ordering' },
],
keywords: ['kanban', 'board', 'feature', 'card', 'dependency', 'graph', 'priority', 'pending', 'progress', 'done'],
},
{
id: 'agent-system',
title: 'Agent System',
icon: Bot,
subsections: [
{ id: 'maestro-orchestrator', title: 'Maestro: The Orchestrator' },
{ id: 'coding-agents', title: 'Coding Agents' },
{ id: 'testing-agents', title: 'Testing Agents' },
{ id: 'agent-lifecycle', title: 'Agent Lifecycle' },
{ id: 'concurrency', title: 'Concurrency Control' },
{ id: 'mission-control', title: 'Agent Mission Control' },
{ id: 'agent-mascots', title: 'Agent Mascots & States' },
{ id: 'agent-logs', title: 'Viewing Agent Logs' },
{ id: 'process-limits', title: 'Process Limits' },
],
keywords: ['agent', 'maestro', 'orchestrator', 'coding', 'testing', 'parallel', 'concurrency', 'mascot', 'spark', 'fizz', 'octo', 'batch'],
},
{
id: 'settings-config',
title: 'Settings & Configuration',
icon: Settings,
subsections: [
{ id: 'opening-settings', title: 'Opening Settings' },
{ id: 'yolo-mode', title: 'YOLO Mode' },
{ id: 'headless-browser', title: 'Headless Browser' },
{ id: 'model-selection', title: 'Model Selection' },
{ id: 'regression-agents', title: 'Regression Agents' },
{ id: 'features-per-agent', title: 'Features per Agent (Batch Size)' },
{ id: 'concurrency-setting', title: 'Concurrency' },
{ id: 'settings-persistence', title: 'How Settings are Persisted' },
],
keywords: ['settings', 'config', 'yolo', 'headless', 'model', 'opus', 'sonnet', 'haiku', 'batch', 'regression'],
},
{
id: 'developer-tools',
title: 'Developer Tools',
icon: Terminal,
subsections: [
{ id: 'debug-panel', title: 'Debug Panel' },
{ id: 'agent-logs-tab', title: 'Agent Logs Tab' },
{ id: 'dev-server-logs', title: 'Dev Server Logs Tab' },
{ id: 'terminal', title: 'Terminal' },
{ id: 'dev-server-control', title: 'Dev Server Control' },
{ id: 'per-agent-logs', title: 'Per-Agent Logs' },
],
keywords: ['debug', 'terminal', 'logs', 'dev server', 'console', 'xterm', 'shell'],
},
{
id: 'ai-assistant',
title: 'AI Assistant',
icon: MessageSquare,
subsections: [
{ id: 'what-is-assistant', title: 'What is the Assistant?' },
{ id: 'opening-assistant', title: 'Opening the Assistant' },
{ id: 'assistant-capabilities', title: 'What It Can Do' },
{ id: 'assistant-limitations', title: 'What It Cannot Do' },
{ id: 'conversation-history', title: 'Conversation History' },
],
keywords: ['assistant', 'ai', 'chat', 'help', 'question', 'conversation'],
},
{
id: 'scheduling',
title: 'Scheduling',
icon: Clock,
subsections: [
{ id: 'what-scheduling-does', title: 'What Scheduling Does' },
{ id: 'creating-schedule', title: 'Creating a Schedule' },
{ id: 'schedule-settings', title: 'Schedule Settings' },
{ id: 'schedule-overrides', title: 'Schedule Overrides' },
{ id: 'crash-recovery', title: 'Crash Recovery' },
],
keywords: ['schedule', 'timer', 'automated', 'cron', 'run', 'recurring', 'utc'],
},
{
id: 'appearance-themes',
title: 'Appearance & Themes',
icon: Palette,
subsections: [
{ id: 'themes-overview', title: 'Themes Overview' },
{ id: 'dark-light-mode', title: 'Dark & Light Mode' },
{ id: 'theme-selector', title: 'Theme Selector' },
{ id: 'keyboard-shortcuts', title: 'Keyboard Shortcuts' },
],
keywords: ['theme', 'dark', 'light', 'color', 'appearance', 'twitter', 'claude', 'neo', 'brutalism', 'retro', 'aurora', 'business', 'keyboard', 'shortcut'],
},
{
id: 'security',
title: 'Security',
icon: Shield,
subsections: [
{ id: 'command-validation', title: 'Command Validation Overview' },
{ id: 'command-hierarchy', title: 'Command Hierarchy' },
{ id: 'hardcoded-blocklist', title: 'Hardcoded Blocklist' },
{ id: 'global-allowlist', title: 'Global Allowlist' },
{ id: 'project-allowlist', title: 'Per-Project Allowed Commands' },
{ id: 'org-config', title: 'Organization Configuration' },
{ id: 'extra-read-paths', title: 'Extra Read Paths' },
{ id: 'filesystem-sandboxing', title: 'Filesystem Sandboxing' },
],
keywords: ['security', 'sandbox', 'allowlist', 'blocklist', 'command', 'bash', 'permission', 'filesystem'],
},
{
id: 'advanced-config',
title: 'Advanced Configuration',
icon: Wrench,
subsections: [
{ id: 'vertex-ai', title: 'Vertex AI Setup' },
{ id: 'ollama', title: 'Ollama Local Models' },
{ id: 'env-variables', title: 'Environment Variables' },
{ id: 'cli-arguments', title: 'CLI Arguments' },
{ id: 'webhooks', title: 'Webhook Support' },
{ id: 'project-registry', title: 'Project Registry' },
],
keywords: ['vertex', 'gcloud', 'ollama', 'local', 'env', 'environment', 'cli', 'webhook', 'n8n', 'registry', 'api'],
},
{
id: 'faq',
title: 'FAQ & Troubleshooting',
icon: HelpCircle,
subsections: [
{ id: 'faq-new-project', title: 'Starting a New Project' },
{ id: 'faq-existing-project', title: 'Adding to Existing Project' },
{ id: 'faq-agent-crash', title: 'Agent Crashes' },
{ id: 'faq-custom-commands', title: 'Custom Bash Commands' },
{ id: 'faq-blocked-features', title: 'Blocked Features' },
{ id: 'faq-parallel', title: 'Running in Parallel' },
{ id: 'faq-local-model', title: 'Using Local Models' },
{ id: 'faq-reset', title: 'Resetting a Project' },
{ id: 'faq-agent-types', title: 'Coding vs Testing Agents' },
{ id: 'faq-real-time', title: 'Monitoring in Real Time' },
],
keywords: ['faq', 'troubleshoot', 'help', 'problem', 'issue', 'fix', 'error', 'stuck', 'reset', 'crash'],
},
]

View File

@@ -0,0 +1,75 @@
/**
* AIAssistant Documentation Section
*
* Covers the project assistant: what it is, how to open it,
* its capabilities and limitations, and conversation history.
*/
import { Badge } from '@/components/ui/badge'
export function AIAssistant() {
return (
<div>
{/* What is the Assistant? */}
<h3 id="what-is-assistant" className="text-lg font-semibold text-foreground mt-8 mb-3">
What is the Assistant?
</h3>
<p className="text-muted-foreground mb-4">
The AI Assistant is a read-only project helper that can answer questions about your project, search
code, view progress, and help you understand what&rsquo;s happening &mdash; without making any changes.
</p>
{/* Opening the Assistant */}
<h3 id="opening-assistant" className="text-lg font-semibold text-foreground mt-8 mb-3">
Opening the Assistant
</h3>
<ul className="list-disc space-y-2 ml-4 text-muted-foreground">
<li>
Press <Badge variant="secondary">A</Badge> to toggle the assistant panel
</li>
<li>Or click the floating action button (chat bubble) in the bottom-right corner</li>
<li>The panel slides in from the right side</li>
</ul>
{/* What It Can Do */}
<h3 id="assistant-capabilities" className="text-lg font-semibold text-foreground mt-8 mb-3">
What It Can Do
</h3>
<ul className="list-disc space-y-2 ml-4 text-muted-foreground">
<li>Read and search your project&rsquo;s source code</li>
<li>Answer questions about code architecture and implementation</li>
<li>View feature progress and status</li>
<li>Create new features based on your description</li>
<li>Explain what agents have done or are currently doing</li>
<li>Help debug issues by analyzing code and logs</li>
</ul>
{/* What It Cannot Do */}
<h3 id="assistant-limitations" className="text-lg font-semibold text-foreground mt-8 mb-3">
What It Cannot Do
</h3>
<ul className="list-disc space-y-2 ml-4 text-muted-foreground">
<li>Modify files (read-only access)</li>
<li>Run bash commands</li>
<li>Mark features as passing/failing</li>
<li>Start or stop agents</li>
<li>Access external APIs or the internet</li>
</ul>
<div className="border-l-4 border-primary pl-4 italic text-muted-foreground mt-4">
This is a deliberate security design &mdash; the assistant is a safe way to interact with your project
without risk of unintended changes.
</div>
{/* Conversation History */}
<h3 id="conversation-history" className="text-lg font-semibold text-foreground mt-8 mb-3">
Conversation History
</h3>
<ul className="list-disc space-y-2 ml-4 text-muted-foreground">
<li>Conversations are stored per-project in SQLite database</li>
<li>Multiple conversations supported &mdash; start new ones as needed</li>
<li>Switch between conversations using the conversation selector</li>
<li>History persists across browser sessions</li>
</ul>
</div>
)
}

View File

@@ -0,0 +1,220 @@
/**
* AdvancedConfig Documentation Section
*
* Covers Vertex AI setup, Ollama local models, environment variables,
* CLI arguments, webhook support, and the project registry.
*/
import { Badge } from '@/components/ui/badge'
/** Environment variable descriptor for the reference table. */
interface EnvVar {
name: string
description: string
}
const ENV_VARS: EnvVar[] = [
{ name: 'CLAUDE_CODE_USE_VERTEX', description: 'Enable Vertex AI (1)' },
{ name: 'CLOUD_ML_REGION', description: 'GCP region' },
{ name: 'ANTHROPIC_VERTEX_PROJECT_ID', description: 'GCP project ID' },
{ name: 'ANTHROPIC_BASE_URL', description: 'Custom API base URL (for Ollama)' },
{ name: 'ANTHROPIC_AUTH_TOKEN', description: 'API auth token' },
{ name: 'API_TIMEOUT_MS', description: 'API timeout in milliseconds' },
{ name: 'EXTRA_READ_PATHS', description: 'Comma-separated extra read directories' },
{ name: 'ANTHROPIC_DEFAULT_OPUS_MODEL', description: 'Override Opus model name' },
{ name: 'ANTHROPIC_DEFAULT_SONNET_MODEL', description: 'Override Sonnet model name' },
{ name: 'ANTHROPIC_DEFAULT_HAIKU_MODEL', description: 'Override Haiku model name' },
]
/** CLI argument descriptor for the reference table. */
interface CliArg {
name: string
description: string
}
const CLI_ARGS: CliArg[] = [
{ name: '--project-dir', description: 'Project directory path or registered name' },
{ name: '--yolo', description: 'Enable YOLO mode' },
{ name: '--parallel', description: 'Enable parallel mode' },
{ name: '--max-concurrency N', description: 'Max concurrent agents (1-5)' },
{ name: '--batch-size N', description: 'Features per coding agent (1-3)' },
{ name: '--batch-features 1,2,3', description: 'Specific feature IDs to implement' },
{ name: '--testing-batch-size N', description: 'Features per testing batch (1-5)' },
{ name: '--testing-batch-features 1,2,3', description: 'Specific testing feature IDs' },
]
export function AdvancedConfig() {
return (
<div>
{/* Vertex AI Setup */}
<h3 id="vertex-ai" className="text-lg font-semibold text-foreground mt-8 mb-3">
Vertex AI Setup
</h3>
<p className="text-muted-foreground mb-3">
Run coding agents via Google Cloud Vertex AI:
</p>
<ol className="list-decimal space-y-2 ml-4 text-muted-foreground">
<li>
Install and authenticate the gcloud CLI:{' '}
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">
gcloud auth application-default login
</span>
</li>
<li>
Configure your{' '}
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">.env</span> file:
</li>
</ol>
<div className="bg-muted rounded-lg p-4 font-mono text-sm mt-3">
<pre><code>{`CLAUDE_CODE_USE_VERTEX=1
CLOUD_ML_REGION=us-east5
ANTHROPIC_VERTEX_PROJECT_ID=your-gcp-project-id
ANTHROPIC_DEFAULT_OPUS_MODEL=claude-opus-4-5@20251101
ANTHROPIC_DEFAULT_SONNET_MODEL=claude-sonnet-4-5@20250929
ANTHROPIC_DEFAULT_HAIKU_MODEL=claude-3-5-haiku@20241022`}</code></pre>
</div>
<blockquote className="border-l-4 border-primary pl-4 italic text-muted-foreground mt-4">
Use <span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono not-italic">@</span>{' '}
instead of <span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono not-italic">-</span>{' '}
in model names for Vertex AI.
</blockquote>
{/* Ollama Local Models */}
<h3 id="ollama" className="text-lg font-semibold text-foreground mt-8 mb-3">
Ollama Local Models
</h3>
<p className="text-muted-foreground mb-3">
Run coding agents using local models via Ollama v0.14.0+:
</p>
<ol className="list-decimal space-y-2 ml-4 text-muted-foreground">
<li>
Install Ollama from{' '}
<a href="https://ollama.com" target="_blank" rel="noreferrer" className="text-primary underline">
ollama.com
</a>
</li>
<li>
Start Ollama:{' '}
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">ollama serve</span>
</li>
<li>
Pull a coding model:{' '}
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">ollama pull qwen3-coder</span>
</li>
<li>
Configure your{' '}
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">.env</span>:
</li>
</ol>
<div className="bg-muted rounded-lg p-4 font-mono text-sm mt-3">
<pre><code>{`ANTHROPIC_BASE_URL=http://localhost:11434
ANTHROPIC_AUTH_TOKEN=ollama
API_TIMEOUT_MS=3000000
ANTHROPIC_DEFAULT_SONNET_MODEL=qwen3-coder`}</code></pre>
</div>
<p className="text-muted-foreground mt-3">
<strong className="text-foreground">Recommended models:</strong>{' '}
<Badge variant="secondary">qwen3-coder</Badge>{' '}
<Badge variant="secondary">deepseek-coder-v2</Badge>{' '}
<Badge variant="secondary">codellama</Badge>
</p>
<p className="text-muted-foreground mt-2">
<strong className="text-foreground">Limitations:</strong> Smaller context windows than Claude
(model-dependent), extended context beta disabled (not supported by Ollama), and performance
depends on local hardware (GPU recommended).
</p>
{/* Environment Variables */}
<h3 id="env-variables" className="text-lg font-semibold text-foreground mt-8 mb-3">
Environment Variables
</h3>
<p className="text-muted-foreground mb-3">
Key environment variables for configuring AutoCoder:
</p>
<table className="w-full text-sm mt-3">
<thead>
<tr className="bg-muted/50">
<th className="border border-border px-3 py-2 text-left font-medium text-foreground">
Variable
</th>
<th className="border border-border px-3 py-2 text-left font-medium text-foreground">
Description
</th>
</tr>
</thead>
<tbody className="text-muted-foreground">
{ENV_VARS.map((v) => (
<tr key={v.name}>
<td className="border border-border px-3 py-2">
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">{v.name}</span>
</td>
<td className="border border-border px-3 py-2">{v.description}</td>
</tr>
))}
</tbody>
</table>
{/* CLI Arguments */}
<h3 id="cli-arguments" className="text-lg font-semibold text-foreground mt-8 mb-3">
CLI Arguments
</h3>
<p className="text-muted-foreground mb-3">
Command-line arguments for{' '}
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">
autonomous_agent_demo.py
</span>
:
</p>
<table className="w-full text-sm mt-3">
<thead>
<tr className="bg-muted/50">
<th className="border border-border px-3 py-2 text-left font-medium text-foreground">
Argument
</th>
<th className="border border-border px-3 py-2 text-left font-medium text-foreground">
Description
</th>
</tr>
</thead>
<tbody className="text-muted-foreground">
{CLI_ARGS.map((arg) => (
<tr key={arg.name}>
<td className="border border-border px-3 py-2">
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">{arg.name}</span>
</td>
<td className="border border-border px-3 py-2">{arg.description}</td>
</tr>
))}
</tbody>
</table>
{/* Webhook Support */}
<h3 id="webhooks" className="text-lg font-semibold text-foreground mt-8 mb-3">
Webhook Support
</h3>
<ul className="list-disc space-y-2 ml-4 text-muted-foreground">
<li>AutoCoder can send webhook notifications on feature completion</li>
<li>Compatible with N8N and similar automation tools</li>
<li>Configure the webhook URL in project settings</li>
<li>
Payload includes: feature name, status, and project info
</li>
</ul>
{/* Project Registry */}
<h3 id="project-registry" className="text-lg font-semibold text-foreground mt-8 mb-3">
Project Registry
</h3>
<ul className="list-disc space-y-2 ml-4 text-muted-foreground">
<li>
All projects are registered in{' '}
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">~/.autocoder/registry.db</span>{' '}
(SQLite)
</li>
<li>Maps project names to filesystem paths</li>
<li>Uses POSIX path format (forward slashes) for cross-platform compatibility</li>
<li>SQLAlchemy ORM with SQLite&apos;s built-in transaction handling</li>
</ul>
</div>
)
}

View File

@@ -0,0 +1,280 @@
/**
* AgentSystem Documentation Section
*
* Covers the orchestrator (Maestro), coding agents, testing agents,
* agent lifecycle, concurrency control, mission control dashboard,
* agent mascots and states, viewing logs, and process limits.
*/
import { Badge } from '@/components/ui/badge'
export function AgentSystem() {
return (
<div>
{/* Maestro: The Orchestrator */}
<h3 id="maestro-orchestrator" className="text-lg font-semibold text-foreground mt-8 mb-3">
Maestro: The Orchestrator
</h3>
<p className="text-muted-foreground mb-3">
Maestro is the central orchestrator that coordinates all agents. It acts as the conductor,
ensuring features are implemented efficiently and in the correct order.
</p>
<ul className="list-disc space-y-2 ml-4 text-muted-foreground">
<li>Manages the full lifecycle of coding and testing agents</li>
<li>Schedules which features to work on based on dependencies and priority</li>
<li>Monitors agent health and restarts crashed agents automatically</li>
<li>Reports status to the UI in real time via WebSocket</li>
</ul>
{/* Coding Agents */}
<h3 id="coding-agents" className="text-lg font-semibold text-foreground mt-8 mb-3">
Coding Agents
</h3>
<ul className="list-disc space-y-2 ml-4 text-muted-foreground">
<li>Implement features one at a time, or in batches of 1&ndash;3</li>
<li>
Claim features atomically via the{' '}
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">
feature_claim_and_get
</span>{' '}
MCP tool &mdash; no two agents work on the same feature
</li>
<li>Run in isolated environments with their own browser context</li>
<li>
Use the Claude Code SDK with project-specific tools and{' '}
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">CLAUDE.md</span>
</li>
</ul>
{/* Testing Agents */}
<h3 id="testing-agents" className="text-lg font-semibold text-foreground mt-8 mb-3">
Testing Agents
</h3>
<ul className="list-disc space-y-2 ml-4 text-muted-foreground">
<li>Run regression tests after features are implemented</li>
<li>Verify that new code does not break existing features</li>
<li>Configurable ratio: 0&ndash;3 testing agents per coding agent</li>
<li>Can batch-test multiple features per session (1&ndash;5)</li>
</ul>
{/* Agent Lifecycle */}
<h3 id="agent-lifecycle" className="text-lg font-semibold text-foreground mt-8 mb-3">
Agent Lifecycle
</h3>
<p className="text-muted-foreground mb-3">
Agents are controlled through the UI or CLI. The lifecycle states are:
</p>
<table className="w-full text-sm mt-3">
<thead>
<tr className="bg-muted/50">
<th className="border border-border px-3 py-2 text-left font-medium text-foreground">
Action
</th>
<th className="border border-border px-3 py-2 text-left font-medium text-foreground">
Behavior
</th>
</tr>
</thead>
<tbody className="text-muted-foreground">
<tr>
<td className="border border-border px-3 py-2 font-medium">Start</td>
<td className="border border-border px-3 py-2">
Click the Play button or run the CLI command
</td>
</tr>
<tr>
<td className="border border-border px-3 py-2 font-medium">Stop</td>
<td className="border border-border px-3 py-2">
Gracefully terminates all running agents
</td>
</tr>
<tr>
<td className="border border-border px-3 py-2 font-medium">Pause</td>
<td className="border border-border px-3 py-2">
Temporarily halts work (agents finish their current task first)
</td>
</tr>
<tr>
<td className="border border-border px-3 py-2 font-medium">Resume</td>
<td className="border border-border px-3 py-2">
Continues from where the agents were paused
</td>
</tr>
</tbody>
</table>
<p className="text-muted-foreground mt-3">
Agents auto-continue between sessions with a 3-second delay, so they keep working until
all features are complete or they are explicitly stopped.
</p>
{/* Concurrency Control */}
<h3 id="concurrency" className="text-lg font-semibold text-foreground mt-8 mb-3">
Concurrency Control
</h3>
<ul className="list-disc space-y-2 ml-4 text-muted-foreground">
<li>
A slider in the agent control bar sets the number of concurrent coding agents
(1&ndash;5)
</li>
<li>
More agents means faster progress, but also higher API usage
</li>
<li>Each agent runs as an independent subprocess</li>
<li>
Feature claiming is atomic &mdash; no two agents will ever work on the same feature
simultaneously
</li>
</ul>
{/* Agent Mission Control */}
<h3 id="mission-control" className="text-lg font-semibold text-foreground mt-8 mb-3">
Agent Mission Control
</h3>
<p className="text-muted-foreground mb-3">
The Mission Control dashboard provides a real-time overview of all active agents:
</p>
<ul className="list-disc space-y-2 ml-4 text-muted-foreground">
<li>Active agent cards with mascot icons and current status</li>
<li>The feature each agent is currently working on</li>
<li>Agent state indicators (thinking, working, testing, etc.)</li>
<li>Orchestrator status and a recent activity feed</li>
</ul>
{/* Agent Mascots & States */}
<h3 id="agent-mascots" className="text-lg font-semibold text-foreground mt-8 mb-3">
Agent Mascots &amp; States
</h3>
<p className="text-muted-foreground mb-3">
Each agent is assigned a unique mascot for easy identification:{' '}
<strong className="text-foreground">Spark</strong>,{' '}
<strong className="text-foreground">Fizz</strong>,{' '}
<strong className="text-foreground">Octo</strong>,{' '}
<strong className="text-foreground">Hoot</strong>,{' '}
<strong className="text-foreground">Buzz</strong>, and more. Agent states include:
</p>
<table className="w-full text-sm mt-3">
<thead>
<tr className="bg-muted/50">
<th className="border border-border px-3 py-2 text-left font-medium text-foreground">
State
</th>
<th className="border border-border px-3 py-2 text-left font-medium text-foreground">
Animation
</th>
<th className="border border-border px-3 py-2 text-left font-medium text-foreground">
Description
</th>
</tr>
</thead>
<tbody className="text-muted-foreground">
<tr>
<td className="border border-border px-3 py-2">
<Badge variant="secondary">Thinking</Badge>
</td>
<td className="border border-border px-3 py-2">Bouncing</td>
<td className="border border-border px-3 py-2">Agent is planning its approach</td>
</tr>
<tr>
<td className="border border-border px-3 py-2">
<Badge variant="secondary">Working</Badge>
</td>
<td className="border border-border px-3 py-2">Shake</td>
<td className="border border-border px-3 py-2">Actively writing code</td>
</tr>
<tr>
<td className="border border-border px-3 py-2">
<Badge variant="secondary">Testing</Badge>
</td>
<td className="border border-border px-3 py-2">Rotating</td>
<td className="border border-border px-3 py-2">Running tests</td>
</tr>
<tr>
<td className="border border-border px-3 py-2">
<Badge variant="default">Success</Badge>
</td>
<td className="border border-border px-3 py-2">Celebration</td>
<td className="border border-border px-3 py-2">Feature completed</td>
</tr>
<tr>
<td className="border border-border px-3 py-2">
<Badge variant="destructive">Error</Badge>
</td>
<td className="border border-border px-3 py-2">Red shake</td>
<td className="border border-border px-3 py-2">Encountered an issue</td>
</tr>
<tr>
<td className="border border-border px-3 py-2">
<Badge variant="outline">Struggling</Badge>
</td>
<td className="border border-border px-3 py-2">Concerned expression</td>
<td className="border border-border px-3 py-2">Multiple consecutive failures</td>
</tr>
</tbody>
</table>
{/* Viewing Agent Logs */}
<h3 id="agent-logs" className="text-lg font-semibold text-foreground mt-8 mb-3">
Viewing Agent Logs
</h3>
<ul className="list-disc space-y-2 ml-4 text-muted-foreground">
<li>Click any agent card in Mission Control to see its log output</li>
<li>Logs are color-coded by level (info, warning, error)</li>
<li>Output streams in real time via WebSocket</li>
<li>Each agent&apos;s logs are isolated and filterable</li>
</ul>
{/* Process Limits */}
<h3 id="process-limits" className="text-lg font-semibold text-foreground mt-8 mb-3">
Process Limits
</h3>
<p className="text-muted-foreground mb-3">
The orchestrator enforces strict bounds on concurrent processes to prevent resource
exhaustion:
</p>
<table className="w-full text-sm mt-3">
<thead>
<tr className="bg-muted/50">
<th className="border border-border px-3 py-2 text-left font-medium text-foreground">
Limit
</th>
<th className="border border-border px-3 py-2 text-left font-medium text-foreground">
Value
</th>
</tr>
</thead>
<tbody className="text-muted-foreground">
<tr>
<td className="border border-border px-3 py-2">
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">
MAX_PARALLEL_AGENTS
</span>
</td>
<td className="border border-border px-3 py-2">5 (maximum concurrent coding agents)</td>
</tr>
<tr>
<td className="border border-border px-3 py-2">
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">
MAX_TOTAL_AGENTS
</span>
</td>
<td className="border border-border px-3 py-2">
10 (hard limit on coding + testing combined)
</td>
</tr>
<tr>
<td className="border border-border px-3 py-2">Testing agents</td>
<td className="border border-border px-3 py-2">
Capped at the same count as coding agents
</td>
</tr>
<tr>
<td className="border border-border px-3 py-2">Total Python processes</td>
<td className="border border-border px-3 py-2">
Never exceeds 11 (1 orchestrator + 5 coding + 5 testing)
</td>
</tr>
</tbody>
</table>
</div>
)
}

View File

@@ -0,0 +1,130 @@
/**
* AppSpecSetup Documentation Section
*
* Explains what an app spec is, how to create one interactively
* or manually, the initializer agent, and starting after spec creation.
*/
export function AppSpecSetup() {
return (
<div>
{/* What is an App Spec? */}
<h3 id="what-is-app-spec" className="text-lg font-semibold text-foreground mt-8 mb-3">
What is an App Spec?
</h3>
<p className="text-muted-foreground mb-3">
The app spec is an XML document that describes the application to be built. It lives at{' '}
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">
.autocoder/prompts/app_spec.txt
</span>{' '}
and tells the initializer agent what features to create. The spec defines your app&apos;s name,
description, tech stack, and the features that should be implemented.
</p>
<div className="bg-muted rounded-lg p-4 font-mono text-sm">
<pre><code>{`<app>
<name>My App</name>
<description>A task management app</description>
<features>
<feature>User authentication with login/signup</feature>
<feature>Task CRUD with categories</feature>
</features>
</app>`}</code></pre>
</div>
{/* Creating a Spec with Claude */}
<h3 id="creating-spec-with-claude" className="text-lg font-semibold text-foreground mt-8 mb-3">
Creating a Spec with Claude
</h3>
<ul className="list-disc space-y-2 ml-4 text-muted-foreground">
<li>
In the UI, select your project and click{' '}
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">Create Spec</span>
</li>
<li>
An interactive chat with Claude helps you define your app &mdash; it asks about
your app&apos;s purpose, features, and tech stack
</li>
<li>The spec is generated and saved automatically</li>
<li>After creation, the initializer agent can be started immediately</li>
</ul>
{/* Writing a Spec Manually */}
<h3 id="writing-spec-manually" className="text-lg font-semibold text-foreground mt-8 mb-3">
Writing a Spec Manually
</h3>
<ul className="list-disc space-y-2 ml-4 text-muted-foreground">
<li>
Create{' '}
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">
.autocoder/prompts/app_spec.txt
</span>{' '}
in your project directory
</li>
<li>
Use XML format with app name, description, tech stack, and a feature list
</li>
<li>
Be specific about each feature &mdash; the initializer creates test cases from these
descriptions
</li>
<li>
Include technical constraints where needed (e.g.,{' '}
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">
&quot;use PostgreSQL&quot;
</span>
,{' '}
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">
&quot;React with TypeScript&quot;
</span>
)
</li>
</ul>
{/* The Initializer Agent */}
<h3 id="initializer-agent" className="text-lg font-semibold text-foreground mt-8 mb-3">
The Initializer Agent
</h3>
<p className="text-muted-foreground mb-3">
The initializer agent is the first agent to run on a new project. It bridges the gap between
your spec and the coding agents that implement features.
</p>
<ul className="list-disc space-y-2 ml-4 text-muted-foreground">
<li>Runs automatically on first agent start when no features exist in the database</li>
<li>Reads the app spec and creates features with descriptions, steps, and priorities</li>
<li>
Sets up feature dependencies (e.g., &quot;auth must be done before user profile&quot;)
</li>
<li>
Creates the feature database at{' '}
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">
.autocoder/features.db
</span>
</li>
</ul>
{/* Starting After Spec Creation */}
<h3 id="starting-after-spec" className="text-lg font-semibold text-foreground mt-8 mb-3">
Starting After Spec Creation
</h3>
<p className="text-muted-foreground mb-3">
Once your spec is ready, you can kick off the agents:
</p>
<ul className="list-disc space-y-2 ml-4 text-muted-foreground">
<li>
From the UI, click the <strong className="text-foreground">Play</strong> button to start
the agent
</li>
<li>
Or run from the CLI:
</li>
</ul>
<div className="bg-muted rounded-lg p-4 font-mono text-sm mt-3">
<pre><code>python autonomous_agent_demo.py --project-dir your-project</code></pre>
</div>
<p className="text-muted-foreground mt-3">
The initializer runs first to create features, then coding agents take over to implement
them. Progress is shown in real time on the Kanban board.
</p>
</div>
)
}

View File

@@ -0,0 +1,185 @@
/**
* AppearanceThemes Documentation Section
*
* Covers built-in themes with color previews, dark/light mode toggling,
* the theme selector dropdown, and global keyboard shortcuts.
*/
import { Badge } from '@/components/ui/badge'
/** Theme descriptor used to render the preview rows. */
interface ThemePreview {
name: string
description: string
colors: { label: string; hex: string }[]
}
const THEMES: ThemePreview[] = [
{
name: 'Twitter',
description: 'Clean, modern blue design. Primary: blue, Background: white/dark gray.',
colors: [
{ label: 'Background', hex: '#ffffff' },
{ label: 'Primary', hex: '#4a9eff' },
{ label: 'Accent', hex: '#e8f4ff' },
],
},
{
name: 'Claude',
description: "Warm beige/cream tones with orange accents. Inspired by Anthropic's Claude brand.",
colors: [
{ label: 'Background', hex: '#faf6f0' },
{ label: 'Primary', hex: '#c75b2a' },
{ label: 'Accent', hex: '#f5ede4' },
],
},
{
name: 'Neo Brutalism',
description: 'Bold colors, hard shadows, no border radius. High contrast, expressive design.',
colors: [
{ label: 'Background', hex: '#ffffff' },
{ label: 'Primary', hex: '#ff4d00' },
{ label: 'Accent', hex: '#ffeb00' },
],
},
{
name: 'Retro Arcade',
description: 'Vibrant pink and teal with pixel-art inspired styling.',
colors: [
{ label: 'Background', hex: '#f0e6d3' },
{ label: 'Primary', hex: '#e8457c' },
{ label: 'Accent', hex: '#4eb8a5' },
],
},
{
name: 'Aurora',
description: 'Deep violet and luminous teal, inspired by the northern lights.',
colors: [
{ label: 'Background', hex: '#faf8ff' },
{ label: 'Primary', hex: '#8b5cf6' },
{ label: 'Accent', hex: '#2dd4bf' },
],
},
{
name: 'Business',
description: 'Professional deep navy and gray monochrome palette for corporate use.',
colors: [
{ label: 'Background', hex: '#eaecef' },
{ label: 'Primary', hex: '#000e4e' },
{ label: 'Accent', hex: '#6b7280' },
],
},
]
/** Keyboard shortcut descriptor for the shortcuts table. */
interface Shortcut {
key: string
action: string
}
const SHORTCUTS: Shortcut[] = [
{ key: '?', action: 'Show keyboard shortcuts help' },
{ key: 'D', action: 'Toggle debug panel' },
{ key: 'T', action: 'Toggle terminal' },
{ key: 'G', action: 'Toggle Kanban/Graph view' },
{ key: 'N', action: 'Add new feature' },
{ key: 'E', action: 'Expand project with AI' },
{ key: 'A', action: 'Toggle AI assistant' },
{ key: ',', action: 'Open settings' },
{ key: 'R', action: 'Reset project' },
{ key: 'Escape', action: 'Close current modal' },
]
export function AppearanceThemes() {
return (
<div>
{/* Themes Overview */}
<h3 id="themes-overview" className="text-lg font-semibold text-foreground mt-8 mb-3">
Themes Overview
</h3>
<p className="text-muted-foreground mb-4">
AutoCoder comes with 6 built-in themes. Each theme provides a complete visual identity including
colors, accents, and dark mode variants.
</p>
<div className="space-y-4">
{THEMES.map((theme) => (
<div key={theme.name} className="flex items-start gap-4">
{/* Color swatches */}
<div className="flex gap-1.5 shrink-0 mt-1">
{theme.colors.map((color) => (
<div
key={color.label}
title={`${color.label}: ${color.hex}`}
className="w-6 h-6 rounded border border-border"
style={{ backgroundColor: color.hex }}
/>
))}
</div>
{/* Description */}
<div>
<strong className="text-foreground">{theme.name}</strong>
{theme.name === 'Twitter' && (
<>
{' '}
<Badge variant="secondary">Default</Badge>
</>
)}
<span className="text-muted-foreground"> &mdash; {theme.description}</span>
</div>
</div>
))}
</div>
{/* Dark & Light Mode */}
<h3 id="dark-light-mode" className="text-lg font-semibold text-foreground mt-8 mb-3">
Dark &amp; Light Mode
</h3>
<ul className="list-disc space-y-2 ml-4 text-muted-foreground">
<li>Toggle with the sun/moon icon in the header</li>
<li>All 6 themes have dedicated dark mode variants</li>
<li>
Preference is saved in browser{' '}
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">localStorage</span>
</li>
<li>Dark mode affects all UI elements including the docs page</li>
</ul>
{/* Theme Selector */}
<h3 id="theme-selector" className="text-lg font-semibold text-foreground mt-8 mb-3">
Theme Selector
</h3>
<ul className="list-disc space-y-2 ml-4 text-muted-foreground">
<li>Hover over the palette icon in the header to open the theme dropdown</li>
<li>Preview themes by hovering over each option (live preview)</li>
<li>Click to select &mdash; the change is applied instantly</li>
<li>Theme preference persists across sessions</li>
</ul>
{/* Keyboard Shortcuts */}
<h3 id="keyboard-shortcuts" className="text-lg font-semibold text-foreground mt-8 mb-3">
Keyboard Shortcuts
</h3>
<p className="text-muted-foreground mb-3">
Press <Badge variant="secondary">?</Badge> anywhere in the UI to see the shortcuts help overlay.
</p>
<table className="w-full text-sm mt-3">
<thead>
<tr className="bg-muted/50">
<th className="border border-border px-3 py-2 text-left font-medium text-foreground">Key</th>
<th className="border border-border px-3 py-2 text-left font-medium text-foreground">Action</th>
</tr>
</thead>
<tbody className="text-muted-foreground">
{SHORTCUTS.map((shortcut) => (
<tr key={shortcut.key}>
<td className="border border-border px-3 py-2">
<Badge variant="secondary">{shortcut.key}</Badge>
</td>
<td className="border border-border px-3 py-2">{shortcut.action}</td>
</tr>
))}
</tbody>
</table>
</div>
)
}

View File

@@ -0,0 +1,104 @@
/**
* DeveloperTools Documentation Section
*
* Covers the debug panel, agent logs tab, dev server logs,
* terminal, dev server control, and per-agent logs.
*/
import { Badge } from '@/components/ui/badge'
export function DeveloperTools() {
return (
<div>
{/* Debug Panel */}
<h3 id="debug-panel" className="text-lg font-semibold text-foreground mt-8 mb-3">
Debug Panel
</h3>
<ul className="list-disc space-y-2 ml-4 text-muted-foreground">
<li>
Press <Badge variant="secondary">D</Badge> to toggle the debug panel at the bottom of the screen
</li>
<li>Resizable by dragging the top edge</li>
<li>
Three tabs: <strong className="text-foreground">Agent Logs</strong>,{' '}
<strong className="text-foreground">Dev Server Logs</strong>, and{' '}
<strong className="text-foreground">Terminal</strong>
</li>
<li>Shows real-time output from agents and dev server</li>
</ul>
{/* Agent Logs Tab */}
<h3 id="agent-logs-tab" className="text-lg font-semibold text-foreground mt-8 mb-3">
Agent Logs Tab
</h3>
<ul className="list-disc space-y-2 ml-4 text-muted-foreground">
<li>
Color-coded log levels:{' '}
<span className="text-[var(--color-log-error)] font-medium">Error</span>,{' '}
<span className="text-[var(--color-log-warning)] font-medium">Warning</span>,{' '}
<span className="text-[var(--color-log-info)] font-medium">Info</span>,{' '}
<span className="text-[var(--color-log-debug)] font-medium">Debug</span>,{' '}
<span className="text-[var(--color-log-success)] font-medium">Success</span>
</li>
<li>Timestamps on each log entry</li>
<li>Auto-scrolls to latest entry</li>
<li>Clear button to reset log view</li>
</ul>
{/* Dev Server Logs Tab */}
<h3 id="dev-server-logs" className="text-lg font-semibold text-foreground mt-8 mb-3">
Dev Server Logs Tab
</h3>
<ul className="list-disc space-y-2 ml-4 text-muted-foreground">
<li>
Shows stdout/stderr from the project&rsquo;s dev server (e.g.,{' '}
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">npm run dev</span>)
</li>
<li>Useful for seeing compilation errors, hot reload status</li>
<li>Clear button available</li>
</ul>
{/* Terminal */}
<h3 id="terminal" className="text-lg font-semibold text-foreground mt-8 mb-3">
Terminal
</h3>
<ul className="list-disc space-y-2 ml-4 text-muted-foreground">
<li>
Press <Badge variant="secondary">T</Badge> to open terminal (opens debug panel on the terminal tab)
</li>
<li>Full xterm.js terminal emulator with WebSocket backend</li>
<li>Multi-tab support: create multiple terminal sessions</li>
<li>Rename tabs by double-clicking the tab title</li>
<li>Each tab runs an independent PTY (pseudo-terminal) session</li>
<li>Supports standard terminal features: colors, cursor movement, history</li>
</ul>
{/* Dev Server Control */}
<h3 id="dev-server-control" className="text-lg font-semibold text-foreground mt-8 mb-3">
Dev Server Control
</h3>
<ul className="list-disc space-y-2 ml-4 text-muted-foreground">
<li>Start/stop button in the header bar</li>
<li>
Auto-detects project type (Next.js, Vite, CRA, etc.) and runs the appropriate dev command
</li>
<li>Shows the dev server URL when running</li>
<li>Automatic crash detection and restart option</li>
<li>Dev server output piped to the Dev Server Logs tab</li>
</ul>
{/* Per-Agent Logs */}
<h3 id="per-agent-logs" className="text-lg font-semibold text-foreground mt-8 mb-3">
Per-Agent Logs
</h3>
<ul className="list-disc space-y-2 ml-4 text-muted-foreground">
<li>In Agent Mission Control, click any agent card to see its individual logs</li>
<li>
Logs include: what feature the agent is working on, code changes, test results
</li>
<li>Separate logs for coding agents and testing agents</li>
<li>Real-time streaming &mdash; see agent output as it happens</li>
</ul>
</div>
)
}

View File

@@ -0,0 +1,157 @@
/**
* FAQ Documentation Section
*
* Covers frequently asked questions about project setup, agent behavior,
* customization, troubleshooting, and real-time monitoring.
*/
export function FAQ() {
return (
<div>
{/* Starting a New Project */}
<h3 id="faq-new-project" className="text-lg font-semibold text-foreground mt-8 mb-3">
Starting a New Project
</h3>
<p className="text-muted-foreground italic mb-2">
How do I use AutoCoder on a new project?
</p>
<p className="text-muted-foreground">
From the UI, select &quot;Create New Project&quot; in the project dropdown. Choose a folder and
name. Then create an app spec using the interactive chat or write one manually. Click Start to run
the initializer agent, which creates features from your spec. Coding agents then implement features
automatically.
</p>
{/* Adding to Existing Project */}
<h3 id="faq-existing-project" className="text-lg font-semibold text-foreground mt-8 mb-3">
Adding to Existing Project
</h3>
<p className="text-muted-foreground italic mb-2">
How do I add AutoCoder to an existing project?
</p>
<p className="text-muted-foreground">
Register the project folder through the UI project selector using &quot;Add Existing&quot;.
AutoCoder creates a{' '}
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">.autocoder/</span> directory
alongside your existing code. Write an app spec describing what to build (new features), and the
agent works within your existing codebase.
</p>
{/* Agent Crashes */}
<h3 id="faq-agent-crash" className="text-lg font-semibold text-foreground mt-8 mb-3">
Agent Crashes
</h3>
<p className="text-muted-foreground italic mb-2">
What happens if an agent crashes?
</p>
<p className="text-muted-foreground">
The orchestrator (Maestro) automatically detects crashed agents and can restart them. Features
claimed by a crashed agent are released back to the pending queue. Scheduled runs use exponential
backoff with up to 3 retries. Check the agent logs in the debug panel for crash details.
</p>
{/* Custom Bash Commands */}
<h3 id="faq-custom-commands" className="text-lg font-semibold text-foreground mt-8 mb-3">
Custom Bash Commands
</h3>
<p className="text-muted-foreground italic mb-2">
How do I customize which bash commands the agent can use?
</p>
<p className="text-muted-foreground">
Create{' '}
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">
.autocoder/allowed_commands.yaml
</span>{' '}
in your project with a list of allowed commands. Supports exact names, wildcards (e.g.,{' '}
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">swift*</span>), and local
scripts. See the Security section for full details on the command hierarchy.
</p>
{/* Blocked Features */}
<h3 id="faq-blocked-features" className="text-lg font-semibold text-foreground mt-8 mb-3">
Blocked Features
</h3>
<p className="text-muted-foreground italic mb-2">
Why are my features stuck in &quot;blocked&quot; status?
</p>
<p className="text-muted-foreground">
Features with unmet dependencies show as blocked. Check the Dependency Graph view (press{' '}
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">G</span>) to see which
features are waiting on others. A feature can only start when all its dependencies are marked as
&quot;passing&quot;. Remove or reorder dependencies if needed.
</p>
{/* Running in Parallel */}
<h3 id="faq-parallel" className="text-lg font-semibold text-foreground mt-8 mb-3">
Running in Parallel
</h3>
<p className="text-muted-foreground italic mb-2">
How do I run multiple agents in parallel?
</p>
<p className="text-muted-foreground">
Use the concurrency slider in the agent control bar (1&ndash;5 agents) or pass{' '}
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">
--parallel --max-concurrency N
</span>{' '}
on the CLI. Each agent claims features atomically, so there is no conflict. More agents means
faster progress but higher API cost.
</p>
{/* Using Local Models */}
<h3 id="faq-local-model" className="text-lg font-semibold text-foreground mt-8 mb-3">
Using Local Models
</h3>
<p className="text-muted-foreground italic mb-2">
Can I use a local model instead of the Claude API?
</p>
<p className="text-muted-foreground">
Yes, via Ollama v0.14.0+. Install Ollama, pull a coding model (e.g.,{' '}
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">qwen3-coder</span>), and
configure your{' '}
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">.env</span> to point to
localhost. See the Advanced Configuration section for full setup instructions.
</p>
{/* Resetting a Project */}
<h3 id="faq-reset" className="text-lg font-semibold text-foreground mt-8 mb-3">
Resetting a Project
</h3>
<p className="text-muted-foreground italic mb-2">
How do I reset a project and start over?
</p>
<p className="text-muted-foreground">
Press <span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">R</span> (when agents
are stopped) to open the Reset modal. Choose between: &quot;Reset Features&quot; (clears the
feature database, keeps the spec) or &quot;Full Reset&quot; (removes the spec too, starts fresh).
After a full reset, you will be prompted to create a new spec.
</p>
{/* Coding vs Testing Agents */}
<h3 id="faq-agent-types" className="text-lg font-semibold text-foreground mt-8 mb-3">
Coding vs Testing Agents
</h3>
<p className="text-muted-foreground italic mb-2">
What&apos;s the difference between coding and testing agents?
</p>
<p className="text-muted-foreground">
Coding agents implement features &mdash; they write code, create files, and run feature-specific
tests. Testing agents run regression tests across completed features to ensure new code does not
break existing functionality. Configure the testing agent ratio (0&ndash;3) in settings.
</p>
{/* Monitoring in Real Time */}
<h3 id="faq-real-time" className="text-lg font-semibold text-foreground mt-8 mb-3">
Monitoring in Real Time
</h3>
<p className="text-muted-foreground italic mb-2">
How do I view what an agent is doing in real time?
</p>
<p className="text-muted-foreground">
Multiple ways: (1) Watch the Kanban board for feature status changes. (2) Open the debug panel
(<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">D</span> key) for live
agent logs. (3) Click agent cards in Mission Control for per-agent logs. (4) The progress bar
updates in real time via WebSocket.
</p>
</div>
)
}

View File

@@ -0,0 +1,182 @@
/**
* FeaturesKanban Documentation Section
*
* Covers the Kanban board, feature cards, dependency graph view,
* adding/editing features, dependencies, expanding with AI,
* and priority ordering.
*/
import { Badge } from '@/components/ui/badge'
export function FeaturesKanban() {
return (
<div>
{/* Kanban Board Overview */}
<h3 id="kanban-overview" className="text-lg font-semibold text-foreground mt-8 mb-3">
Kanban Board Overview
</h3>
<p className="text-muted-foreground mb-3">
The main view organizes features into three columns representing their current status:
</p>
<table className="w-full text-sm mt-3 mb-4">
<thead>
<tr className="bg-muted/50">
<th className="border border-border px-3 py-2 text-left font-medium text-foreground">
Column
</th>
<th className="border border-border px-3 py-2 text-left font-medium text-foreground">
Color
</th>
<th className="border border-border px-3 py-2 text-left font-medium text-foreground">
Meaning
</th>
</tr>
</thead>
<tbody className="text-muted-foreground">
<tr>
<td className="border border-border px-3 py-2 font-medium">Pending</td>
<td className="border border-border px-3 py-2">
<Badge variant="outline" className="border-yellow-500 text-yellow-600">Yellow</Badge>
</td>
<td className="border border-border px-3 py-2">Waiting to be picked up</td>
</tr>
<tr>
<td className="border border-border px-3 py-2 font-medium">In Progress</td>
<td className="border border-border px-3 py-2">
<Badge variant="outline" className="border-cyan-500 text-cyan-600">Cyan</Badge>
</td>
<td className="border border-border px-3 py-2">An agent is actively working on it</td>
</tr>
<tr>
<td className="border border-border px-3 py-2 font-medium">Done</td>
<td className="border border-border px-3 py-2">
<Badge variant="outline" className="border-green-500 text-green-600">Green</Badge>
</td>
<td className="border border-border px-3 py-2">Implemented and passing</td>
</tr>
</tbody>
</table>
<p className="text-muted-foreground">
Each feature appears as a card showing its name, priority, and category. The board updates
in real time as agents work.
</p>
{/* Feature Cards */}
<h3 id="feature-cards" className="text-lg font-semibold text-foreground mt-8 mb-3">
Feature Cards
</h3>
<ul className="list-disc space-y-2 ml-4 text-muted-foreground">
<li>
Each card displays a priority badge (<Badge variant="secondary">P1</Badge> through{' '}
<Badge variant="secondary">P5</Badge>), a category tag, and the feature name
</li>
<li>Status icons indicate the current state of the feature</li>
<li>Click a card to open the detail modal with the full description and test steps</li>
<li>
Cards in the &quot;In Progress&quot; column show which agent is currently working on them
</li>
</ul>
{/* Dependency Graph View */}
<h3 id="dependency-graph" className="text-lg font-semibold text-foreground mt-8 mb-3">
Dependency Graph View
</h3>
<p className="text-muted-foreground mb-3">
An alternative to the Kanban board that visualizes feature relationships as a directed graph.
</p>
<ul className="list-disc space-y-2 ml-4 text-muted-foreground">
<li>
Press <Badge variant="secondary">G</Badge> to toggle between Kanban and Graph view
</li>
<li>Uses the dagre layout engine for automatic node positioning</li>
<li>
Nodes are colored by status &mdash; pending, in-progress, and done each have
distinct colors
</li>
<li>Arrows show dependency relationships between features</li>
<li>Click any node to open the feature detail modal</li>
<li>Supports both horizontal and vertical layout orientations</li>
</ul>
{/* Adding Features */}
<h3 id="adding-features" className="text-lg font-semibold text-foreground mt-8 mb-3">
Adding Features
</h3>
<ul className="list-disc space-y-2 ml-4 text-muted-foreground">
<li>
Press <Badge variant="secondary">N</Badge> to open the Add Feature form
</li>
<li>Fill in: name, description, category, and priority</li>
<li>Optionally define steps (test criteria the agent must pass to complete the feature)</li>
<li>New features are added to the Pending column immediately</li>
</ul>
{/* Editing & Deleting Features */}
<h3 id="editing-features" className="text-lg font-semibold text-foreground mt-8 mb-3">
Editing &amp; Deleting Features
</h3>
<ul className="list-disc space-y-2 ml-4 text-muted-foreground">
<li>Click a feature card to open the detail modal</li>
<li>
Click <strong className="text-foreground">Edit</strong> to modify the name, description,
category, priority, or steps
</li>
<li>
<strong className="text-foreground">Delete</strong> removes the feature permanently
</li>
<li>
<strong className="text-foreground">Skip</strong> moves a feature to the end of the queue
without deleting it
</li>
</ul>
{/* Feature Dependencies */}
<h3 id="feature-dependencies" className="text-lg font-semibold text-foreground mt-8 mb-3">
Feature Dependencies
</h3>
<p className="text-muted-foreground mb-3">
Features can declare dependencies on other features, ensuring they are implemented in the
correct order.
</p>
<ul className="list-disc space-y-2 ml-4 text-muted-foreground">
<li>Set dependencies in the feature edit modal</li>
<li>
Cycle detection prevents circular dependencies (uses Kahn&apos;s algorithm combined
with DFS)
</li>
<li>
Blocked features display a lock icon and cannot be claimed by agents until their
dependencies are met
</li>
<li>The Dependency Graph view makes these relationships easy to visualize</li>
</ul>
{/* Expanding Project with AI */}
<h3 id="expanding-with-ai" className="text-lg font-semibold text-foreground mt-8 mb-3">
Expanding Project with AI
</h3>
<ul className="list-disc space-y-2 ml-4 text-muted-foreground">
<li>
Press <Badge variant="secondary">E</Badge> to open the Expand Project modal
</li>
<li>Chat with Claude to describe the new features you want to add</li>
<li>Supports image attachments for UI mockups or design references</li>
<li>Claude creates properly structured features with appropriate dependencies</li>
<li>New features appear on the board immediately after creation</li>
</ul>
{/* Priority & Ordering */}
<h3 id="feature-priority" className="text-lg font-semibold text-foreground mt-8 mb-3">
Priority &amp; Ordering
</h3>
<ul className="list-disc space-y-2 ml-4 text-muted-foreground">
<li>
Features are ordered by priority: <Badge variant="secondary">P1</Badge> is the highest
and <Badge variant="secondary">P5</Badge> is the lowest
</li>
<li>Within the same priority level, features are ordered by creation time</li>
<li>Agents always pick up the highest-priority ready feature first</li>
</ul>
</div>
)
}

View File

@@ -0,0 +1,134 @@
/**
* GettingStarted Documentation Section
*
* Covers what AutoCoder is, quick start commands,
* creating and adding projects, and system requirements.
*/
import { Badge } from '@/components/ui/badge'
export function GettingStarted() {
return (
<div>
{/* What is AutoCoder? */}
<h3 id="what-is-autocoder" className="text-lg font-semibold text-foreground mt-8 mb-3">
What is AutoCoder?
</h3>
<p className="text-muted-foreground mb-4">
AutoCoder is an autonomous coding agent system that builds complete applications over multiple
sessions using a two-agent pattern:
</p>
<ol className="list-decimal space-y-2 ml-4 text-muted-foreground">
<li>
<strong className="text-foreground">Initializer Agent</strong> &mdash; reads your app spec
and creates features in a SQLite database
</li>
<li>
<strong className="text-foreground">Coding Agent</strong> &mdash; implements features one by
one, marking each as passing when complete
</li>
</ol>
<p className="text-muted-foreground mt-4">
It comes with a React-based UI for monitoring progress, managing features, and controlling agents
in real time.
</p>
{/* Quick Start */}
<h3 id="quick-start" className="text-lg font-semibold text-foreground mt-8 mb-3">
Quick Start
</h3>
<p className="text-muted-foreground mb-3">
Launch AutoCoder with a single command. The CLI menu lets you create or select a project,
while the Web UI provides a full dashboard experience.
</p>
<div className="bg-muted rounded-lg p-4 font-mono text-sm">
<pre><code>{`# Windows
start.bat # CLI menu
start_ui.bat # Web UI
# macOS/Linux
./start.sh # CLI menu
./start_ui.sh # Web UI`}</code></pre>
</div>
{/* Creating a New Project */}
<h3 id="creating-a-project" className="text-lg font-semibold text-foreground mt-8 mb-3">
Creating a New Project
</h3>
<ul className="list-disc space-y-2 ml-4 text-muted-foreground">
<li>
From the UI, click the project dropdown and select{' '}
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">Create New Project</span>
</li>
<li>Enter a name and select or browse to a folder for the project</li>
<li>
Create an app spec interactively with Claude, or write one manually in XML format
</li>
<li>
The initializer agent reads your spec and creates features automatically
</li>
</ul>
{/* Adding to an Existing Project */}
<h3 id="existing-project" className="text-lg font-semibold text-foreground mt-8 mb-3">
Adding to an Existing Project
</h3>
<ul className="list-disc space-y-2 ml-4 text-muted-foreground">
<li>Register the project folder via the UI project selector</li>
<li>
AutoCoder creates a{' '}
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">.autocoder/</span>{' '}
directory inside your project
</li>
<li>
Existing code is preserved &mdash; AutoCoder adds its configuration alongside it
</li>
<li>Write or generate an app spec describing what to build</li>
</ul>
{/* System Requirements */}
<h3 id="system-requirements" className="text-lg font-semibold text-foreground mt-8 mb-3">
System Requirements
</h3>
<table className="w-full text-sm mt-3">
<thead>
<tr className="bg-muted/50">
<th className="border border-border px-3 py-2 text-left font-medium text-foreground">
Requirement
</th>
<th className="border border-border px-3 py-2 text-left font-medium text-foreground">
Details
</th>
</tr>
</thead>
<tbody className="text-muted-foreground">
<tr>
<td className="border border-border px-3 py-2">Python</td>
<td className="border border-border px-3 py-2">
<Badge variant="secondary">3.11+</Badge>
</td>
</tr>
<tr>
<td className="border border-border px-3 py-2">Node.js</td>
<td className="border border-border px-3 py-2">
<Badge variant="secondary">20+</Badge>{' '}
<span className="text-xs">(for UI development)</span>
</td>
</tr>
<tr>
<td className="border border-border px-3 py-2">Claude Code CLI</td>
<td className="border border-border px-3 py-2">
Required for running agents
</td>
</tr>
<tr>
<td className="border border-border px-3 py-2">Operating System</td>
<td className="border border-border px-3 py-2">
Windows, macOS, or Linux
</td>
</tr>
</tbody>
</table>
</div>
)
}

View File

@@ -0,0 +1,162 @@
/**
* ProjectStructure Documentation Section
*
* Covers the .autocoder/ directory layout, features database,
* prompts directory, allowed commands, CLAUDE.md convention,
* legacy migration, and Claude inheritance.
*/
export function ProjectStructure() {
return (
<div>
{/* .autocoder/ Directory Layout */}
<h3 id="autocoder-directory" className="text-lg font-semibold text-foreground mt-8 mb-3">
.autocoder/ Directory Layout
</h3>
<p className="text-muted-foreground mb-3">
Every AutoCoder project stores its configuration and runtime files in a{' '}
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">.autocoder/</span>{' '}
directory at the project root.
</p>
<div className="bg-muted rounded-lg p-4 font-mono text-sm">
<pre><code>{`your-project/
\u251C\u2500\u2500 .autocoder/
\u2502 \u251C\u2500\u2500 features.db # SQLite feature database
\u2502 \u251C\u2500\u2500 .agent.lock # Lock file (prevents multiple instances)
\u2502 \u251C\u2500\u2500 .gitignore # Ignores runtime files
\u2502 \u251C\u2500\u2500 allowed_commands.yaml # Per-project bash command allowlist
\u2502 \u2514\u2500\u2500 prompts/
\u2502 \u251C\u2500\u2500 app_spec.txt # Application specification (XML)
\u2502 \u251C\u2500\u2500 initializer_prompt.md # First session prompt
\u2502 \u2514\u2500\u2500 coding_prompt.md # Continuation session prompt
\u251C\u2500\u2500 CLAUDE.md # Claude Code convention file
\u2514\u2500\u2500 app_spec.txt # Root copy for template compatibility`}</code></pre>
</div>
{/* Features Database */}
<h3 id="features-db" className="text-lg font-semibold text-foreground mt-8 mb-3">
Features Database
</h3>
<ul className="list-disc space-y-2 ml-4 text-muted-foreground">
<li>
SQLite database managed by SQLAlchemy, stored at{' '}
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">
.autocoder/features.db
</span>
</li>
<li>
Each feature record includes: id, priority, category, name, description, steps, status
(<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">pending</span>,{' '}
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">in_progress</span>,{' '}
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">passing</span>,{' '}
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">failing</span>),
and dependencies
</li>
<li>Agents interact with features through MCP server tools, not direct database access</li>
<li>Viewable in the UI via the Kanban board or the Dependency Graph view</li>
</ul>
{/* Prompts Directory */}
<h3 id="prompts-directory" className="text-lg font-semibold text-foreground mt-8 mb-3">
Prompts Directory
</h3>
<p className="text-muted-foreground mb-3">
Prompts control how agents behave during each session:
</p>
<ul className="list-disc space-y-2 ml-4 text-muted-foreground">
<li>
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">app_spec.txt</span>{' '}
&mdash; your application specification in XML format
</li>
<li>
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">
initializer_prompt.md
</span>{' '}
&mdash; prompt for the initializer agent (creates features from the spec)
</li>
<li>
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">
coding_prompt.md
</span>{' '}
&mdash; prompt for coding agents (implements features)
</li>
</ul>
<p className="text-muted-foreground mt-3">
These can be customized per project. If not present, defaults from{' '}
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">
.claude/templates/
</span>{' '}
are used as a fallback.
</p>
{/* Allowed Commands Config */}
<h3 id="allowed-commands-yaml" className="text-lg font-semibold text-foreground mt-8 mb-3">
Allowed Commands Config
</h3>
<p className="text-muted-foreground mb-3">
The optional{' '}
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">
.autocoder/allowed_commands.yaml
</span>{' '}
file lets you grant project-specific bash commands to the agent. This is useful when your
project requires tools beyond the default allowlist (e.g., language-specific compilers or
custom build scripts).
</p>
<p className="text-muted-foreground">
See the <strong className="text-foreground">Security</strong> section for full details on
the command hierarchy and how project-level commands interact with global and organization
policies.
</p>
{/* CLAUDE.md Convention */}
<h3 id="claude-md" className="text-lg font-semibold text-foreground mt-8 mb-3">
CLAUDE.md Convention
</h3>
<ul className="list-disc space-y-2 ml-4 text-muted-foreground">
<li>
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">CLAUDE.md</span>{' '}
lives at the project root, as required by the Claude Code SDK
</li>
<li>
Contains project-specific instructions that the agent follows during every coding session
</li>
<li>
Automatically inherited by all agents working on the project &mdash; no additional
configuration needed
</li>
</ul>
{/* Legacy Layout Migration */}
<h3 id="legacy-migration" className="text-lg font-semibold text-foreground mt-8 mb-3">
Legacy Layout Migration
</h3>
<p className="text-muted-foreground mb-3">
Older projects stored configuration files directly at the project root (e.g.,{' '}
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">features.db</span>,{' '}
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">prompts/</span>).
</p>
<ul className="list-disc space-y-2 ml-4 text-muted-foreground">
<li>
On the next agent start, these files are automatically migrated into{' '}
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">.autocoder/</span>
</li>
<li>Dual-path resolution ensures both old and new layouts work transparently</li>
<li>No manual migration is needed &mdash; it happens seamlessly</li>
</ul>
{/* Claude Inheritance */}
<h3 id="claude-inheritance" className="text-lg font-semibold text-foreground mt-8 mb-3">
Claude Inheritance
</h3>
<p className="text-muted-foreground mb-3">
Agents inherit all MCP servers, tools, skills, custom commands, and{' '}
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">CLAUDE.md</span>{' '}
from the target project folder.
</p>
<div className="border-l-4 border-primary pl-4 italic text-muted-foreground">
If your project has its own MCP servers or Claude commands, the coding agent can use them.
The agent essentially runs as if Claude Code was opened in your project directory.
</div>
</div>
)
}

View File

@@ -0,0 +1,102 @@
/**
* Scheduling Documentation Section
*
* Covers schedule creation, per-schedule settings,
* overrides, and crash recovery with exponential backoff.
*/
import { Badge } from '@/components/ui/badge'
export function Scheduling() {
return (
<div>
{/* What Scheduling Does */}
<h3 id="what-scheduling-does" className="text-lg font-semibold text-foreground mt-8 mb-3">
What Scheduling Does
</h3>
<p className="text-muted-foreground mb-4">
Scheduling automates agent runs at specific times. Set up a schedule and AutoCoder will automatically
start agents on your project &mdash; useful for overnight builds, periodic maintenance, or continuous
development.
</p>
{/* Creating a Schedule */}
<h3 id="creating-schedule" className="text-lg font-semibold text-foreground mt-8 mb-3">
Creating a Schedule
</h3>
<ul className="list-disc space-y-2 ml-4 text-muted-foreground">
<li>Click the clock icon in the header to open the Schedule modal</li>
<li>Set: start time, duration (how long agents run), days of the week</li>
<li>Optionally configure: YOLO mode, concurrency, model selection</li>
<li>Schedule is saved and starts at the next matching time</li>
</ul>
{/* Schedule Settings */}
<h3 id="schedule-settings" className="text-lg font-semibold text-foreground mt-8 mb-3">
Schedule Settings
</h3>
<p className="text-muted-foreground mb-3">
Each schedule can override global settings:
</p>
<table className="w-full text-sm mt-3">
<thead>
<tr className="bg-muted/50">
<th className="border border-border px-3 py-2 text-left font-medium text-foreground">Setting</th>
<th className="border border-border px-3 py-2 text-left font-medium text-foreground">Details</th>
</tr>
</thead>
<tbody className="text-muted-foreground">
<tr>
<td className="border border-border px-3 py-2">YOLO mode</td>
<td className="border border-border px-3 py-2">On/off per schedule</td>
</tr>
<tr>
<td className="border border-border px-3 py-2">Concurrency</td>
<td className="border border-border px-3 py-2">
<Badge variant="secondary">1&ndash;5</Badge> agents
</td>
</tr>
<tr>
<td className="border border-border px-3 py-2">Model tier</td>
<td className="border border-border px-3 py-2">Opus / Sonnet / Haiku</td>
</tr>
<tr>
<td className="border border-border px-3 py-2">Duration</td>
<td className="border border-border px-3 py-2">How long the session runs before auto-stopping</td>
</tr>
</tbody>
</table>
<div className="border-l-4 border-primary pl-4 italic text-muted-foreground mt-4">
All schedule times are in UTC timezone.
</div>
{/* Schedule Overrides */}
<h3 id="schedule-overrides" className="text-lg font-semibold text-foreground mt-8 mb-3">
Schedule Overrides
</h3>
<ul className="list-disc space-y-2 ml-4 text-muted-foreground">
<li>Manually skip a scheduled run (one-time override)</li>
<li>Pause a schedule temporarily (resumes on next period)</li>
<li>
View upcoming runs with{' '}
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">Running until</span> /{' '}
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">Next run</span> indicators
</li>
<li>Override without deleting the schedule</li>
</ul>
{/* Crash Recovery */}
<h3 id="crash-recovery" className="text-lg font-semibold text-foreground mt-8 mb-3">
Crash Recovery
</h3>
<ul className="list-disc space-y-2 ml-4 text-muted-foreground">
<li>If a scheduled agent crashes, it uses exponential backoff for retries</li>
<li>
Maximum <Badge variant="secondary">3</Badge> retry attempts per scheduled run
</li>
<li>Backoff prevents rapid restart loops</li>
<li>Failed runs are logged for troubleshooting</li>
</ul>
</div>
)
}

View File

@@ -0,0 +1,218 @@
/**
* Security Documentation Section
*
* Covers the defense-in-depth security model: command validation layers,
* the hierarchical allowlist/blocklist system, per-project and org-level
* configuration, extra read paths, and filesystem sandboxing.
*/
import { Badge } from '@/components/ui/badge'
export function Security() {
return (
<div>
{/* Command Validation Overview */}
<h3 id="command-validation" className="text-lg font-semibold text-foreground mt-8 mb-3">
Command Validation Overview
</h3>
<p className="text-muted-foreground mb-3">
AutoCoder uses a defense-in-depth approach for security. All three layers must pass before any
command is executed:
</p>
<ol className="list-decimal space-y-2 ml-4 text-muted-foreground">
<li>
<strong className="text-foreground">OS-level sandbox</strong> &mdash; bash commands run inside
a restricted sandbox environment
</li>
<li>
<strong className="text-foreground">Filesystem restriction</strong> &mdash; agents can only
access the project directory (plus configured extra read paths)
</li>
<li>
<strong className="text-foreground">Hierarchical allowlist</strong> &mdash; every bash command
is validated against a multi-level allowlist system
</li>
</ol>
{/* Command Hierarchy */}
<h3 id="command-hierarchy" className="text-lg font-semibold text-foreground mt-8 mb-3">
Command Hierarchy
</h3>
<p className="text-muted-foreground mb-3">
Commands are evaluated against a 5-level hierarchy, from highest to lowest priority:
</p>
<ol className="list-decimal space-y-2 ml-4 text-muted-foreground">
<li>
<strong className="text-foreground">Hardcoded Blocklist</strong>{' '}
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">security.py</span>{' '}
&mdash; NEVER allowed, cannot be overridden
</li>
<li>
<strong className="text-foreground">Org Blocklist</strong>{' '}
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">~/.autocoder/config.yaml</span>{' '}
&mdash; org-wide blocks, cannot be project-overridden
</li>
<li>
<strong className="text-foreground">Org Allowlist</strong>{' '}
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">~/.autocoder/config.yaml</span>{' '}
&mdash; available to all projects
</li>
<li>
<strong className="text-foreground">Global Allowlist</strong>{' '}
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">security.py</span>{' '}
&mdash; default commands (npm, git, curl, etc.)
</li>
<li>
<strong className="text-foreground">Project Allowlist</strong>{' '}
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">
.autocoder/allowed_commands.yaml
</span>{' '}
&mdash; project-specific additions
</li>
</ol>
<blockquote className="border-l-4 border-primary pl-4 italic text-muted-foreground mt-4">
Higher priority levels always win. A command blocked at level 1 or 2 can never be allowed by
lower levels.
</blockquote>
{/* Hardcoded Blocklist */}
<h3 id="hardcoded-blocklist" className="text-lg font-semibold text-foreground mt-8 mb-3">
Hardcoded Blocklist
</h3>
<p className="text-muted-foreground mb-3">
The following commands can <strong className="text-foreground">never</strong> be allowed, regardless
of any configuration. They are hardcoded in{' '}
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">security.py</span> and
cannot be overridden:
</p>
<div className="flex flex-wrap gap-2">
{['dd', 'sudo', 'su', 'shutdown', 'reboot', 'poweroff', 'mkfs', 'fdisk', 'mount', 'umount', 'systemctl'].map(
(cmd) => (
<Badge key={cmd} variant="destructive">
{cmd}
</Badge>
),
)}
</div>
{/* Global Allowlist */}
<h3 id="global-allowlist" className="text-lg font-semibold text-foreground mt-8 mb-3">
Global Allowlist
</h3>
<p className="text-muted-foreground mb-3">
Default commands available to all projects out of the box. These are the standard development
commands needed for most projects:
</p>
<div className="flex flex-wrap gap-2">
{['npm', 'npx', 'node', 'git', 'curl', 'python', 'pip', 'cat', 'ls', 'mkdir', 'cp', 'mv', 'rm', 'grep', 'find'].map(
(cmd) => (
<Badge key={cmd} variant="secondary">
{cmd}
</Badge>
),
)}
</div>
{/* Per-Project Allowed Commands */}
<h3 id="project-allowlist" className="text-lg font-semibold text-foreground mt-8 mb-3">
Per-Project Allowed Commands
</h3>
<p className="text-muted-foreground mb-3">
Each project can define additional allowed commands in{' '}
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">
.autocoder/allowed_commands.yaml
</span>
:
</p>
<div className="bg-muted rounded-lg p-4 font-mono text-sm">
<pre><code>{`# .autocoder/allowed_commands.yaml
version: 1
commands:
# Exact command name
- name: swift
description: Swift compiler
# Wildcard - matches swiftc, swiftlint, swiftformat
- name: swift*
description: All Swift tools (wildcard)
# Local project scripts
- name: ./scripts/build.sh
description: Project build script`}</code></pre>
</div>
<p className="text-muted-foreground mt-3">
<strong className="text-foreground">Pattern matching:</strong> exact match (
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">swift</span>), wildcard (
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">swift*</span> matches swiftc,
swiftlint, etc.), and scripts (
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">./scripts/build.sh</span>).
Limit: 100 commands per project.
</p>
{/* Organization Configuration */}
<h3 id="org-config" className="text-lg font-semibold text-foreground mt-8 mb-3">
Organization Configuration
</h3>
<p className="text-muted-foreground mb-3">
System administrators can set org-wide policies in{' '}
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">~/.autocoder/config.yaml</span>:
</p>
<div className="bg-muted rounded-lg p-4 font-mono text-sm">
<pre><code>{`# ~/.autocoder/config.yaml
version: 1
# Commands available to ALL projects
allowed_commands:
- name: jq
description: JSON processor
# Commands blocked across ALL projects (cannot be overridden)
blocked_commands:
- aws # Prevent accidental cloud operations
- kubectl # Block production deployments`}</code></pre>
</div>
<p className="text-muted-foreground mt-3">
Org-level blocked commands cannot be overridden by any project configuration.
</p>
{/* Extra Read Paths */}
<h3 id="extra-read-paths" className="text-lg font-semibold text-foreground mt-8 mb-3">
Extra Read Paths
</h3>
<p className="text-muted-foreground mb-3">
Allow agents to read files from directories outside the project folder via the{' '}
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">EXTRA_READ_PATHS</span>{' '}
environment variable:
</p>
<div className="bg-muted rounded-lg p-4 font-mono text-sm">
<pre><code>EXTRA_READ_PATHS=/path/to/docs,/path/to/shared-libs</code></pre>
</div>
<ul className="list-disc space-y-2 ml-4 text-muted-foreground mt-3">
<li>Must be absolute paths and must exist as directories</li>
<li>Only read operations allowed (Read, Glob, Grep &mdash; no Write/Edit)</li>
<li>
Sensitive directories are always blocked:{' '}
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">.ssh</span>,{' '}
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">.aws</span>,{' '}
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">.gnupg</span>,{' '}
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">.docker</span>,{' '}
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">.kube</span>, etc.
</li>
</ul>
{/* Filesystem Sandboxing */}
<h3 id="filesystem-sandboxing" className="text-lg font-semibold text-foreground mt-8 mb-3">
Filesystem Sandboxing
</h3>
<ul className="list-disc space-y-2 ml-4 text-muted-foreground">
<li>Agents can only write to the project directory</li>
<li>Read access is limited to the project directory plus configured extra read paths</li>
<li>
Path traversal attacks are prevented via canonicalization (
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">Path.resolve()</span>)
</li>
<li>File operations are validated before execution</li>
</ul>
</div>
)
}

View File

@@ -0,0 +1,188 @@
/**
* SettingsConfig Documentation Section
*
* Covers global settings: opening the modal, YOLO mode, headless browser,
* model selection, regression agents, batch size, concurrency, and persistence.
*/
import { Badge } from '@/components/ui/badge'
export function SettingsConfig() {
return (
<div>
{/* Opening Settings */}
<h3 id="opening-settings" className="text-lg font-semibold text-foreground mt-8 mb-3">
Opening Settings
</h3>
<p className="text-muted-foreground mb-4">
Press the <Badge variant="secondary">,</Badge> (comma) key or click the gear icon in the header bar to
open the Settings modal. Settings are global and apply to all projects.
</p>
{/* YOLO Mode */}
<h3 id="yolo-mode" className="text-lg font-semibold text-foreground mt-8 mb-3">
YOLO Mode
</h3>
<p className="text-muted-foreground mb-3">
YOLO mode is for rapid prototyping &mdash; it skips testing for faster iteration:
</p>
<ul className="list-disc space-y-2 ml-4 text-muted-foreground">
<li>
<strong className="text-foreground">What&rsquo;s skipped:</strong> Regression testing, Playwright MCP
server (browser automation disabled)
</li>
<li>
<strong className="text-foreground">What still runs:</strong> Lint and type-check (to verify code
compiles), Feature MCP server for tracking
</li>
<li>
Toggle via the lightning bolt button in the UI or the{' '}
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">--yolo</span> CLI flag
</li>
<li>
<strong className="text-foreground">When to use:</strong> Early prototyping when you want to scaffold
features quickly without verification overhead
</li>
<li>Switch back to standard mode for production-quality development</li>
</ul>
{/* Headless Browser */}
<h3 id="headless-browser" className="text-lg font-semibold text-foreground mt-8 mb-3">
Headless Browser
</h3>
<ul className="list-disc space-y-2 ml-4 text-muted-foreground">
<li>When enabled, Playwright runs without a visible browser window</li>
<li>Saves CPU/GPU resources on machines running multiple agents</li>
<li>Tests still run fully &mdash; just no visible browser UI</li>
<li>Toggle in settings or via the UI button</li>
</ul>
{/* Model Selection */}
<h3 id="model-selection" className="text-lg font-semibold text-foreground mt-8 mb-3">
Model Selection
</h3>
<p className="text-muted-foreground mb-3">
Choose which Claude model tier to use for your agents:
</p>
<table className="w-full text-sm mt-3">
<thead>
<tr className="bg-muted/50">
<th className="border border-border px-3 py-2 text-left font-medium text-foreground">Tier</th>
<th className="border border-border px-3 py-2 text-left font-medium text-foreground">
Characteristics
</th>
</tr>
</thead>
<tbody className="text-muted-foreground">
<tr>
<td className="border border-border px-3 py-2">
<Badge variant="default">Opus</Badge>
</td>
<td className="border border-border px-3 py-2">Most capable, highest quality</td>
</tr>
<tr>
<td className="border border-border px-3 py-2">
<Badge variant="secondary">Sonnet</Badge>
</td>
<td className="border border-border px-3 py-2">Balanced speed and quality</td>
</tr>
<tr>
<td className="border border-border px-3 py-2">
<Badge variant="outline">Haiku</Badge>
</td>
<td className="border border-border px-3 py-2">Fastest, most economical</td>
</tr>
</tbody>
</table>
<ul className="list-disc space-y-2 ml-4 text-muted-foreground mt-4">
<li>Model can be set globally in settings</li>
<li>Per-schedule model override is also available</li>
<li>
When using Vertex AI, model names use{' '}
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">@</span> instead of{' '}
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">-</span> (e.g.,{' '}
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">
claude-opus-4-5@20251101
</span>
)
</li>
</ul>
{/* Regression Agents */}
<h3 id="regression-agents" className="text-lg font-semibold text-foreground mt-8 mb-3">
Regression Agents
</h3>
<p className="text-muted-foreground mb-3">
Controls how many testing agents run alongside coding agents (0&ndash;3):
</p>
<ul className="list-disc space-y-2 ml-4 text-muted-foreground">
<li>
<strong className="text-foreground">0:</strong> No regression testing (like YOLO but coding agents
still test their own feature)
</li>
<li>
<strong className="text-foreground">1:</strong> One testing agent runs in background verifying
completed features
</li>
<li>
<strong className="text-foreground">2&ndash;3:</strong> Multiple testing agents for thorough
verification
</li>
<li>Testing agents batch-test 1&ndash;5 features per session</li>
</ul>
{/* Features per Agent / Batch Size */}
<h3 id="features-per-agent" className="text-lg font-semibold text-foreground mt-8 mb-3">
Features per Agent (Batch Size)
</h3>
<p className="text-muted-foreground mb-3">
Controls how many features each coding agent implements per session (1&ndash;3):
</p>
<ul className="list-disc space-y-2 ml-4 text-muted-foreground">
<li>
<strong className="text-foreground">1:</strong> One feature per session (most focused, lower risk of
conflicts)
</li>
<li>
<strong className="text-foreground">2&ndash;3:</strong> Multiple features per session (more efficient,
fewer session startups)
</li>
<li>
Set via settings UI or the{' '}
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">--batch-size</span> CLI flag
</li>
<li>
Can also target specific features:{' '}
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">--batch-features 1,2,3</span>
</li>
</ul>
{/* Concurrency */}
<h3 id="concurrency-setting" className="text-lg font-semibold text-foreground mt-8 mb-3">
Concurrency
</h3>
<ul className="list-disc space-y-2 ml-4 text-muted-foreground">
<li>Per-project default concurrency saved in project settings</li>
<li>Override at runtime with the concurrency slider in agent controls</li>
<li>
Range: <Badge variant="secondary">1&ndash;5</Badge> concurrent coding agents
</li>
<li>Higher concurrency = faster progress but more API cost</li>
</ul>
{/* How Settings are Persisted */}
<h3 id="settings-persistence" className="text-lg font-semibold text-foreground mt-8 mb-3">
How Settings are Persisted
</h3>
<ul className="list-disc space-y-2 ml-4 text-muted-foreground">
<li>
Global settings stored in SQLite registry at{' '}
<span className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">~/.autocoder/registry.db</span>
</li>
<li>Per-project settings (like default concurrency) stored in the project registry entry</li>
<li>UI settings (theme, dark mode) stored in browser localStorage</li>
<li>Settings survive app restarts and are shared across UI sessions</li>
</ul>
</div>
)
}

View File

@@ -0,0 +1,36 @@
import { useState, useEffect, useCallback } from 'react'
export type Route = 'app' | 'docs'
interface HashRouteState {
route: Route
section: string | null
navigate: (hash: string) => void
}
function parseHash(hash: string): { route: Route; section: string | null } {
const cleaned = hash.replace(/^#\/?/, '')
if (cleaned === 'docs' || cleaned.startsWith('docs/')) {
const section = cleaned.slice(5) || null // Remove 'docs/' prefix
return { route: 'docs', section }
}
return { route: 'app', section: null }
}
export function useHashRoute(): HashRouteState {
const [state, setState] = useState(() => parseHash(window.location.hash))
useEffect(() => {
const handleHashChange = () => {
setState(parseHash(window.location.hash))
}
window.addEventListener('hashchange', handleHashChange)
return () => window.removeEventListener('hashchange', handleHashChange)
}, [])
const navigate = useCallback((hash: string) => {
window.location.hash = hash
}, [])
return { ...state, navigate }
}

View File

@@ -1,7 +1,9 @@
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { useHashRoute } from './hooks/useHashRoute'
import App from './App'
import { DocsPage } from './components/docs/DocsPage'
import './styles/globals.css'
// Note: Custom theme removed - using shadcn/ui theming instead
@@ -14,10 +16,16 @@ const queryClient = new QueryClient({
},
})
function Router() {
const { route } = useHashRoute()
if (route === 'docs') return <DocsPage />
return <App />
}
createRoot(document.getElementById('root')!).render(
<StrictMode>
<QueryClientProvider client={queryClient}>
<App />
<Router />
</QueryClientProvider>
</StrictMode>,
)

View File

@@ -1134,6 +1134,143 @@
}
}
/* ============================================================================
Documentation Prose Typography
============================================================================ */
.docs-prose {
line-height: 1.7;
color: var(--muted-foreground);
}
.docs-prose h2 {
font-size: 1.5rem;
font-weight: 700;
color: var(--foreground);
margin-top: 3rem;
margin-bottom: 1rem;
padding-bottom: 0.5rem;
border-bottom: 2px solid var(--border);
scroll-margin-top: 5rem;
}
.docs-prose h2:first-child {
margin-top: 0;
}
.docs-prose h3 {
font-size: 1.15rem;
font-weight: 600;
color: var(--foreground);
margin-top: 2rem;
margin-bottom: 0.75rem;
scroll-margin-top: 5rem;
}
.docs-prose p {
margin-bottom: 1rem;
max-width: 65ch;
}
.docs-prose ul,
.docs-prose ol {
margin-bottom: 1rem;
padding-left: 1.5rem;
}
.docs-prose ul {
list-style-type: disc;
}
.docs-prose ol {
list-style-type: decimal;
}
.docs-prose li {
margin-bottom: 0.375rem;
}
.docs-prose li > ul,
.docs-prose li > ol {
margin-top: 0.375rem;
margin-bottom: 0;
}
.docs-prose pre {
background: var(--muted);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 1rem;
overflow-x: auto;
margin-bottom: 1rem;
font-family: var(--font-mono);
font-size: 0.8125rem;
line-height: 1.6;
}
.docs-prose code:not(pre code) {
background: var(--muted);
padding: 0.125rem 0.375rem;
border-radius: 0.25rem;
font-family: var(--font-mono);
font-size: 0.8125rem;
}
.docs-prose table {
width: 100%;
border-collapse: collapse;
margin-bottom: 1rem;
font-size: 0.875rem;
}
.docs-prose th {
background: var(--muted);
font-weight: 600;
color: var(--foreground);
text-align: left;
padding: 0.5rem 0.75rem;
border: 1px solid var(--border);
}
.docs-prose td {
padding: 0.5rem 0.75rem;
border: 1px solid var(--border);
}
.docs-prose tr:nth-child(even) td {
background: var(--muted);
opacity: 0.5;
}
.docs-prose blockquote {
border-left: 4px solid var(--primary);
padding-left: 1rem;
margin-bottom: 1rem;
font-style: italic;
color: var(--muted-foreground);
}
.docs-prose a {
color: var(--primary);
text-decoration: underline;
text-underline-offset: 2px;
}
.docs-prose a:hover {
opacity: 0.8;
}
.docs-prose strong {
color: var(--foreground);
font-weight: 600;
}
.docs-prose hr {
border: none;
border-top: 1px solid var(--border);
margin: 2rem 0;
}
/* ============================================================================
Scrollbar Styling
============================================================================ */