### Install just Source: https://github.com/asermax/tachikoma/blob/master/docs/architecture/ADR-005-task-runner.md Commands to install the just task runner on various platforms. ```bash # Arch Linux sudo pacman -S just # macOS brew install just # Cargo cargo install just # Other: see https://github.com/casey/just#installation ``` -------------------------------- ### Install Tachikoma Source: https://github.com/asermax/tachikoma/blob/master/README.md Install the Tachikoma tool globally using uv. ```bash uv tool install tachikoma ``` -------------------------------- ### Install Project Dependencies Source: https://github.com/asermax/tachikoma/blob/master/CLAUDE.md Use this command to synchronize all project dependencies. ```bash just install # uv sync --all-groups ``` -------------------------------- ### Install and Run Tachikoma Source: https://context7.com/asermax/tachikoma/llms.txt Install Tachikoma globally, set your Anthropic API key, and run the agent via the CLI. Supports REPL and Telegram channels. ```bash # Install Tachikoma globally as a CLI tool uv tool install tachikoma ``` ```bash # Set your Anthropic API key export ANTHROPIC_API_KEY="your-key-here" ``` ```bash # Run the agent (starts REPL by default) tachikoma ``` ```bash # Or use the explicit run command tachikoma run ``` ```bash # Run with Telegram channel tachikoma run --channel telegram ``` ```bash # Upgrade to latest version uv tool upgrade tachikoma ``` -------------------------------- ### Initialize components with Bootstrap hooks Source: https://context7.com/asermax/tachikoma/llms.txt Shows how to define custom initialization hooks and register them with the Bootstrap system to manage workspace setup. ```python import asyncio from tachikoma.bootstrap import Bootstrap, BootstrapContext, BootstrapError from tachikoma.config import SettingsManager async def custom_hook(ctx: BootstrapContext) -> None: """Example bootstrap hook for custom initialization.""" settings = ctx.settings_manager.settings workspace = settings.workspace.path # Check if initialization is needed custom_dir = workspace / "custom" if custom_dir.exists(): return # Already initialized, skip # Prompt user if needed if ctx.settings_manager.settings.channel == "repl": response = ctx.prompt("Initialize custom features? [y/N]: ") if response.lower() != "y": return # Perform initialization custom_dir.mkdir(parents=True, exist_ok=True) # Store objects for later use via extras bag ctx.extras["custom_dir"] = custom_dir async def bootstrap_example(): settings_manager = SettingsManager() bootstrap = Bootstrap(settings_manager) # Register hooks in execution order bootstrap.register("workspace", workspace_hook) bootstrap.register("logging", logging_hook) bootstrap.register("database", database_hook) bootstrap.register("custom", custom_hook) try: await bootstrap.run() except BootstrapError as e: print(f"Bootstrap failed: {e}") return # Retrieve objects from extras bag custom_dir = bootstrap.extras.get("custom_dir") database = bootstrap.extras["database"] print(f"Bootstrap complete. Database: {database}") # Note: workspace_hook, logging_hook, database_hook are built-in hooks asyncio.run(bootstrap_example()) ``` -------------------------------- ### Complete Agent Definition Example Source: https://github.com/asermax/tachikoma/blob/master/src/tachikoma/skills/builtin/skill-authoring-guide/references/agents.md A comprehensive example of an agent definition, including YAML frontmatter and a detailed markdown system prompt. ```yaml --- description: "Analyzes code diffs for potential issues" model: opus tools: - Read - Glob - Grep --- # Code Diff Analyzer You are a code review specialist. Analyze code changes for quality issues. ## Input You will receive a code diff and the project's coding standards. ## Your Task 1. Review the diff for: - Logic errors or bugs - Style violations - Missing tests - Security concerns 2. Check surrounding context if needed (use Read/Glob/Grep) ## Output Format Provide findings as: ### Critical Issues - [Issue with file:line reference] ### Suggestions - [Improvement opportunity] ### Notes - [Observation without action required] ``` -------------------------------- ### Structured Logging with Context Source: https://github.com/asermax/tachikoma/blob/master/docs/design/DES-002-logging-conventions.md Use structured logging with key=value pairs and .bind() for context like component names. This example shows module-level binding and exception logging with tracebacks. ```python from loguru import logger # Module-level bound logger _log = logger.bind(component="coordinator") async def send_message(self, message: str) -> AsyncIterator[Event]: _log.debug("Message received: length={n}", n=len(message)) try: async for event in self._client.send(message): yield event _log.debug("Response complete") except Exception as e: _log.exception("Message processing failed: error={err}", err=str(e)) raise ``` -------------------------------- ### Example Skill Definition Source: https://github.com/asermax/tachikoma/blob/master/src/tachikoma/skills/builtin/skill-authoring-guide/SKILL.md This YAML defines a skill for managing git commits. It includes a description, trigger conditions, and workflow steps. Use this as a template for defining new skills. ```yaml --- description: | Activates when the user wants to create, update, or manage git commits. Triggers on requests to commit changes, create a commit, make a commit. --- # Git Commit Workflow Guides the user through creating well-structured git commits. ## When to Use Use this skill when: - User asks to commit changes - User wants to create a commit with a specific message - User needs help with commit message format ## Workflow 1. **Stage changes**: Review what files have been modified 2. **Draft message**: Propose a conventional commit message 3. **Create commit**: Execute the git commit ## Tips - Use conventional commit format (type(scope): message) - Group related changes into logical commits - Keep commits focused and atomic ``` -------------------------------- ### SQLAlchemy 2.0 Async ORM Setup Source: https://github.com/asermax/tachikoma/blob/master/docs/feature-designs/agent/sessions.md Illustrates the choice to use SQLAlchemy 2.0 with an async ORM and `aiosqlite` backend for typed ORM models and schema creation. This approach provides a robust persistence pattern for the project. ```python # Example usage of SQLAlchemy 2.0 async ORM (conceptual) # from sqlalchemy.ext.asyncio import create_async_engine # from sqlalchemy.orm import Mapped, declarative_base, sessionmaker # Base = declarative_base() # class Session(Base): # __tablename__ = 'sessions' # id: Mapped[int] = mapped_column(Integer, primary_key=True) # # ... other columns # engine = create_async_engine( # "sqlite+aiosqlite:///./test.db", connect_args={"check_same_thread": False} # ) # AsyncSessionLocal = sessionmaker( # engine, class_=AsyncSession, expire_on_commit=False # ) # async def get_db(): # async with AsyncSessionLocal() as session: # yield session ``` -------------------------------- ### Explaining Reasoning in Skill Content Source: https://github.com/asermax/tachikoma/blob/master/src/tachikoma/skills/builtin/skill-authoring-guide/SKILL.md Example of providing reasoning behind a choice in skill content, enhancing assistant understanding. ```markdown # Good Use the `deep-analysis` agent for complex multi-file reasoning. This agent has access to all tools and can explore the codebase thoroughly. # Why: Complex analysis often requires reading multiple files, searching # for patterns, and understanding relationships. The agent pattern keeps # this focused and tool-equipped. ``` -------------------------------- ### Custom Context Provider for Pre-Processing Source: https://context7.com/asermax/tachikoma/llms.txt Implement a custom context provider by inheriting from `ContextProvider` and overriding the `provide` method. This example adds weather-related context when the message contains 'weather'. Ensure the `ContextProvider` is registered with the `PreProcessingPipeline`. ```python import asyncio from tachikoma.pre_processing import ( PreProcessingPipeline, ContextProvider, ContextResult, assemble_context ) from tachikoma.agent_defaults import AgentDefaults from pathlib import Path class CustomContextProvider(ContextProvider): """Example custom context provider.""" async def provide(self, message: str) -> ContextResult | None: # Return context relevant to the message if "weather" in message.lower(): return ContextResult( tag="weather-context", content="User location: San Francisco, CA", mcp_servers=None, agents=None ) return None async def preprocessing_example(): # Create pipeline and register providers pipeline = PreProcessingPipeline() pipeline.register(CustomContextProvider()) # Run providers in parallel message = "What's the weather like today?" results = await pipeline.run(message) # Assemble context into enriched message enriched = assemble_context(results, message) print(enriched) # Output: # # User location: San Francisco, CA # # # What's the weather like today? # Results can also include MCP servers and agent definitions for result in results: print(f"Tag: {result.tag}") if result.mcp_servers: print(f"MCP Servers: {list(result.mcp_servers.keys())}") if result.agents: print(f"Agents: {list(result.agents.keys())}") asyncio.run(preprocessing_example()) ``` -------------------------------- ### MemoryContextProvider Query Example Source: https://github.com/asermax/tachikoma/blob/master/docs/feature-designs/memory/memory-context-retrieval.md Illustrates how the MemoryContextProvider uses a standalone query with an Opus agent and specific options to search for memories. The query is directed towards the workspace path and uses allowed tools for searching. ```python query(prompt, options=ClaudeAgentOptions( model="opus", effort="low", allowed_tools=["Read", "Glob", "Grep"], max_turns=8, cwd=workspace_path, permission_mode="bypassPermissions" )) → ContextResult(tag="memories", content=...) or None ``` -------------------------------- ### Async Test Example Source: https://github.com/asermax/tachikoma/blob/master/docs/design/DES-001-testing-conventions.md Example of an asynchronous test function using Pytest fixtures and async/await syntax. No explicit `@pytest.mark.asyncio` is needed when `asyncio_mode` is set to `auto`. ```python class TestCoordinatorSendMessage: """Tests for Coordinator.send_message().""" async def test_yields_text_chunk_for_assistant_text( self, coordinator: Coordinator, mock_query: AsyncMock, ) -> None: """AC: Agent responds with text content.""" events = [e async for e in coordinator.send_message("hello")] text_events = [e for e in events if isinstance(e, TextChunk)] assert len(text_events) > 0 assert text_events[0].text == "Hello!" ``` -------------------------------- ### Schedule tasks with TaskRepository Source: https://context7.com/asermax/tachikoma/llms.txt Demonstrates creating, listing, and updating task definitions, as well as exposing them via an MCP server. ```python import asyncio from datetime import datetime, UTC from tachikoma.tasks import ( TaskRepository, TaskDefinition, TaskInstance, ScheduleConfig, create_task_tools_server, instance_generator, session_task_scheduler, background_task_runner ) from tachikoma.database import Database async def task_scheduling_example(): # Initialize database and repository database = Database("sqlite+aiosqlite:///~/.tachikoma/tachikoma.db") await database.initialize() repository = TaskRepository(database.session_maker) # Create a recurring session task (delivered when user is idle) daily_standup = TaskDefinition( id="task-001", name="Daily Standup Reminder", schedule=ScheduleConfig(type="cron", expression="0 9 * * *"), # 9 AM daily task_type="session", prompt="Remind me to check my calendar and prepare for today's meetings.", enabled=True, notify=None, created_at=datetime.now(UTC) ) await repository.create_definition(daily_standup) # Create a one-shot background task (runs independently) backup_task = TaskDefinition( id="task-002", name="Weekly Backup", schedule=ScheduleConfig( type="once", at=datetime(2026, 4, 10, 2, 0, tzinfo=UTC) ), task_type="background", prompt="Run the backup script at ~/scripts/backup.sh and report results.", enabled=True, notify="Inform user of backup completion status.", created_at=datetime.now(UTC) ) await repository.create_definition(backup_task) # List all enabled task definitions definitions = await repository.list_enabled_definitions() for d in definitions: print(f"Task: {d.name} [{d.task_type}] - {d.schedule.type}") # Update a task await repository.update_definition( "task-001", schedule=ScheduleConfig(type="cron", expression="0 8 * * 1-5"), # 8 AM weekdays prompt="Prepare for the day: check calendar, review todos, and set priorities." ) # Create MCP server for agent-driven task management task_tools = create_task_tools_server(repository) # This server exposes: list_tasks, create_task, update_task, delete_task asyncio.run(task_scheduling_example()) ``` -------------------------------- ### Bootstrap and Provider Contract Flow Source: https://github.com/asermax/tachikoma/blob/master/docs/feature-designs/agent/skills.md Visualizes the initialization of the skill registry during bootstrap and the subsequent provider execution flow. ```text skills_hook(ctx) │ ├── workspace_skills_path = workspace_path / "skills" ├── Creates workspace_skills_path directory (idempotent) ├── Resolves builtin_path = Path(__file__).parent / "builtin" │ ├─ Exists → include in sources │ └─ Missing → log warning, skip ├── Creates SkillRegistry([builtin_path, workspace_skills_path]) └── ctx.extras["skill_registry"] = registry __main__.py (after bootstrap.run()) │ ├── skill_registry = bootstrap.extras["skill_registry"] └── SkillsContextProvider(agent_defaults, skill_registry) SkillsContextProvider.provide(message) │ ├── Calls registry.refresh() (dirty check → re-scan all sources if needed) ├── Loads skill names + descriptions from registry.skills ├── Classifies via query() [Opus low effort, DES-007] ├── Reads skill.body from registry (pre-loaded or refreshed) ├── Filters agents via registry.get_agents_for_skill() └── Returns ContextResult(tag="skills", content=XML, agents=filtered_dict) │ └── Pipeline collects results → Coordinator extracts agents │ ▼ Coordinator._agents = merged agents from results │ └── ClaudeAgentOptions(agents=self._agents) ``` -------------------------------- ### Upgrade Tachikoma Source: https://github.com/asermax/tachikoma/blob/master/README.md Update the installed tool to the latest version. ```bash uv tool upgrade tachikoma ``` -------------------------------- ### Run the Agent Source: https://github.com/asermax/tachikoma/blob/master/CLAUDE.md Execute the agent. By default, it runs in a REPL. Use the --channel flag to specify an alternative. ```bash just run # run the agent (REPL by default) just run --channel telegram # run via Telegram ``` -------------------------------- ### Get Current Git Branch Source: https://github.com/asermax/tachikoma/blob/master/docs/feature-designs/agent/project-management.md Command to retrieve the current checked-out branch of a git repository. ```bash git -C symbolic-ref --short HEAD ``` -------------------------------- ### Specific Skill Description Triggers Source: https://github.com/asermax/tachikoma/blob/master/src/tachikoma/skills/builtin/skill-authoring-guide/SKILL.md Example of a specific and effective description for skill detection, focusing on concrete actions. ```yaml # Good: Specific triggers description: "Activates when the user wants to create, define, or scaffold a new skill" ``` -------------------------------- ### Get Default Git Branch Source: https://github.com/asermax/tachikoma/blob/master/docs/feature-designs/agent/project-management.md Command to retrieve the default branch of a git repository's remote origin. ```bash git -C symbolic-ref refs/remotes/origin/HEAD ``` -------------------------------- ### Get Git HEAD Commit Hash Source: https://github.com/asermax/tachikoma/blob/master/docs/feature-designs/agent/project-management.md Command to retrieve the commit hash of the current HEAD in a git repository. ```bash git -C rev-parse HEAD ``` -------------------------------- ### Implement Prompt-Driven Processor Source: https://github.com/asermax/tachikoma/blob/master/docs/design/DES-004-prompt-driven-forked-processor.md Extend PromptDrivenProcessor and call super().__init__() with a prompt constant and AgentDefaults. This is the recommended approach for simple prompt-driven processors. ```python from tachikoma.agent_defaults import AgentDefaults from tachikoma.post_processing import PromptDrivenProcessor MY_PROMPT = """ You are a memory extraction agent... Instructions: 1. Read existing files... 2. Analyze the conversation... 3. Create or update files... """ class MyProcessor(PromptDrivenProcessor): """Processor that extracts memories from conversations.""" def __init__(self, agent_defaults: AgentDefaults) -> None: super().__init__(MY_PROMPT, agent_defaults) ``` -------------------------------- ### Context Entry Loading Source: https://github.com/asermax/tachikoma/blob/master/docs/feature-designs/agent/sessions.md Explains the process for loading context entries before client creation. The registry delegates to the repository for fetching entries, and errors during this process propagate to the caller for graceful degradation. ```text 1. Coordinator calls registry.load_context_entries(session_id) before each client creation 2. Registry delegates to repository.load_context_entries(session_id) 3. Repository SELECT ... WHERE session_id = ? ORDER BY id ASC 4. Returns list[SessionContextEntry] via to_domain() 5. On failure: SessionRepositoryError propagates to caller (coordinator handles graceful degradation by falling back to base preamble only) ``` -------------------------------- ### Agent Namespacing Example Source: https://github.com/asermax/tachikoma/blob/master/src/tachikoma/skills/builtin/skill-authoring-guide/references/agents.md Agents are namespaced using the format `skill-name/agent-name`. Use the full namespaced name when invoking an agent. ```markdown skills/ └── code-review/ └── agents/ └── analyzer.md # → code-review/analyzer ``` -------------------------------- ### Avoiding False Positives in Descriptions Source: https://github.com/asermax/tachikoma/blob/master/src/tachikoma/skills/builtin/skill-authoring-guide/SKILL.md Provides an example of a skill description that avoids triggering on unrelated mentions, focusing only on authoring intent. ```yaml # Good: Only triggers on authoring intent description: | Activates when creating, defining, or setting up a new skill. Does NOT trigger when listing or using existing skills. ``` -------------------------------- ### Tool Scoping Example Source: https://github.com/asermax/tachikoma/blob/master/src/tachikoma/skills/builtin/skill-authoring-guide/references/agents.md The `tools` field in the frontmatter restricts the tools an agent can access. An empty list means no tool access. ```yaml tools: - Read - Glob - Grep ```