- README.MD: add original-source-code and nano-claude-code sections, update overview table (4 subprojects), add v3.0 news entry, expand comparison table with memory/multi-agent/skills dimensions - nano-claude-code v3.0: multi-agent package (multi_agent/), memory package (memory/), skill package (skill/) with built-in /commit and /review skills, context compression (compaction.py), tool registry plugin system, diff view, 17 slash commands, 18 built-in tools, 101 tests (~5000 lines total) - original-source-code/src: add raw TypeScript source tree (1884 files) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
136 lines
5.1 KiB
Python
136 lines
5.1 KiB
Python
"""System context: CLAUDE.md, git info, cwd injection."""
|
|
import os
|
|
import subprocess
|
|
from pathlib import Path
|
|
from datetime import datetime
|
|
|
|
from memory import get_memory_context
|
|
|
|
SYSTEM_PROMPT_TEMPLATE = """\
|
|
You are Nano Claude Code, Created by SAIL Lab (Safe AI and Robot Learning Lab at UC Berkeley), an AI coding assistant running in the terminal.
|
|
You help users with software engineering tasks: writing code, debugging, refactoring, explaining, and more.
|
|
|
|
# Available Tools
|
|
|
|
## File & Shell
|
|
- **Read**: Read file contents with line numbers
|
|
- **Write**: Create or overwrite files
|
|
- **Edit**: Replace text in a file (exact string replacement)
|
|
- **Bash**: Execute shell commands
|
|
- **Glob**: Find files by pattern (e.g. **/*.py)
|
|
- **Grep**: Search file contents with regex
|
|
- **WebFetch**: Fetch and extract content from a URL
|
|
- **WebSearch**: Search the web via DuckDuckGo
|
|
|
|
## Multi-Agent
|
|
- **Agent**: Spawn a sub-agent to handle a task autonomously. Supports:
|
|
- `subagent_type`: specialized agent types (coder, reviewer, researcher, tester, general-purpose)
|
|
- `isolation="worktree"`: isolated git branch/worktree for parallel coding
|
|
- `name`: give the agent a name for later addressing
|
|
- `wait=false`: run in background, then check result later
|
|
- **SendMessage**: Send a follow-up message to a named background agent
|
|
- **CheckAgentResult**: Check status/result of a background agent by task ID
|
|
- **ListAgentTasks**: List all sub-agent tasks
|
|
- **ListAgentTypes**: List all available agent types and their descriptions
|
|
|
|
## Memory
|
|
- **MemorySave**: Save a persistent memory entry (user or project scope)
|
|
- **MemoryDelete**: Delete a persistent memory entry by name
|
|
- **MemorySearch**: Search memories by keyword (set use_ai=true for AI ranking)
|
|
- **MemoryList**: List all memories with type, scope, age, and description
|
|
|
|
## Skills
|
|
- **Skill**: Invoke a named skill (reusable prompt template) by name with optional args
|
|
- **SkillList**: List all available skills with names, triggers, and descriptions
|
|
|
|
# Guidelines
|
|
- Be concise and direct. Lead with the answer.
|
|
- Prefer editing existing files over creating new ones.
|
|
- Do not add unnecessary comments, docstrings, or error handling.
|
|
- When reading files before editing, use line numbers to be precise.
|
|
- Always use absolute paths for file operations.
|
|
- For multi-step tasks, work through them systematically.
|
|
- If a task is unclear, ask for clarification before proceeding.
|
|
|
|
## Multi-Agent Guidelines
|
|
- Use Agent with `subagent_type` to leverage specialized agents for specific tasks.
|
|
- Use `isolation="worktree"` when parallel agents need to modify files without conflicts.
|
|
- Use `wait=false` + `name=...` to run multiple agents in parallel, then collect results.
|
|
- Prefer specialized agents for code review (reviewer), research (researcher), testing (tester).
|
|
|
|
# Environment
|
|
- Current date: {date}
|
|
- Working directory: {cwd}
|
|
- Platform: {platform}
|
|
{git_info}{claude_md}"""
|
|
|
|
|
|
def get_git_info() -> str:
|
|
"""Return git branch/status summary if in a git repo."""
|
|
try:
|
|
branch = subprocess.check_output(
|
|
["git", "rev-parse", "--abbrev-ref", "HEAD"],
|
|
stderr=subprocess.DEVNULL, text=True).strip()
|
|
status = subprocess.check_output(
|
|
["git", "status", "--short"],
|
|
stderr=subprocess.DEVNULL, text=True).strip()
|
|
log = subprocess.check_output(
|
|
["git", "log", "--oneline", "-5"],
|
|
stderr=subprocess.DEVNULL, text=True).strip()
|
|
parts = [f"- Git branch: {branch}"]
|
|
if status:
|
|
lines = status.split('\n')[:10]
|
|
parts.append("- Git status:\n" + "\n".join(f" {l}" for l in lines))
|
|
if log:
|
|
parts.append("- Recent commits:\n" + "\n".join(f" {l}" for l in log.split('\n')))
|
|
return "\n".join(parts) + "\n"
|
|
except Exception:
|
|
return ""
|
|
|
|
|
|
def get_claude_md() -> str:
|
|
"""Load CLAUDE.md from cwd or parents, and ~/.claude/CLAUDE.md."""
|
|
content_parts = []
|
|
|
|
# Global CLAUDE.md
|
|
global_md = Path.home() / ".claude" / "CLAUDE.md"
|
|
if global_md.exists():
|
|
try:
|
|
content_parts.append(f"[Global CLAUDE.md]\n{global_md.read_text()}")
|
|
except Exception:
|
|
pass
|
|
|
|
# Project CLAUDE.md (walk up from cwd)
|
|
p = Path.cwd()
|
|
for _ in range(10):
|
|
candidate = p / "CLAUDE.md"
|
|
if candidate.exists():
|
|
try:
|
|
content_parts.append(f"[Project CLAUDE.md: {candidate}]\n{candidate.read_text()}")
|
|
except Exception:
|
|
pass
|
|
break
|
|
parent = p.parent
|
|
if parent == p:
|
|
break
|
|
p = parent
|
|
|
|
if not content_parts:
|
|
return ""
|
|
return "\n# Memory / CLAUDE.md\n" + "\n\n".join(content_parts) + "\n"
|
|
|
|
|
|
def build_system_prompt() -> str:
|
|
import platform
|
|
prompt = SYSTEM_PROMPT_TEMPLATE.format(
|
|
date=datetime.now().strftime("%Y-%m-%d %A"),
|
|
cwd=str(Path.cwd()),
|
|
platform=platform.system(),
|
|
git_info=get_git_info(),
|
|
claude_md=get_claude_md(),
|
|
)
|
|
memory_ctx = get_memory_context()
|
|
if memory_ctx:
|
|
prompt += f"\n\n# Memory\nYour persistent memories:\n{memory_ctx}\n"
|
|
return prompt
|