Co-authored-by: Kimi Claw <kimi@timmytime.ai> Co-committed-by: Kimi Claw <kimi@timmytime.ai>
9.4 KiB
Job Profiles Design Document
[ROUTING] Streamline local Timmy automation context per job
Issue: timmy-config #90
Author: Timmy (AI Agent)
Date: 2026-03-30
Status: Design Complete - Ready for Implementation
Executive Summary
Local Hermes sessions experience context thrashing when all 40 tools (~9,261 tokens of schema) are loaded for every job. This design introduces job-specific toolset profiles that narrow the tool surface based on task type, achieving 73-91% token reduction and preventing the "loop or thrash" behavior observed in long-running automation.
Problem Statement
When toolsets: [all] is enabled (current default in ~/.hermes/config.yaml), every AIAgent instantiation loads:
- 40 tools across 12+ toolsets
- ~9,261 tokens of JSON schema
- Full browser automation (12 tools)
- Vision, image generation, TTS, MoA reasoning
- All MCP servers (Morrowind, etc.)
For a simple cron job checking Gitea issues, this is massive overkill. The LLM:
- Sees too many options
- Hallucinates tool calls that aren't needed
- Gets confused about which tool to use
- Loops trying different approaches
Solution Overview
Leverage the existing enabled_toolsets parameter in AIAgent.__init__() to create job profiles—pre-defined toolset combinations optimized for specific automation types.
Key Design Decisions
| Decision | Rationale |
|---|---|
| Use YAML profiles, not code | Easy to extend without deployment |
| Map to existing toolsets | No changes needed to Hermes core |
| 5 base profiles | Covers 95% of automation needs |
| Token estimates in comments | Helps users understand trade-offs |
Profile Specifications
1. CODE-WORK Profile
Purpose: Software development, git operations, code review
toolsets: [terminal, file]
tools_enabled: 6
token_estimate: "~2,194 tokens"
token_savings: "~76%"
Included Tools:
terminal,process- git, builds, shell commandsread_file,search_files,write_file,patch
Use Cases:
- Automated code review
- Refactoring tasks
- Build and test automation
- Git branch management
Not Included:
- Web search (assumes local docs/code)
- Browser automation
- Vision/image generation
2. RESEARCH Profile
Purpose: Information gathering, documentation lookup, analysis
toolsets: [web, browser, file]
tools_enabled: 15
token_estimate: "~2,518 tokens"
token_savings: "~73%"
Included Tools:
web_search,web_extract- quick lookups- Full browser suite (12 tools) - deep research
- File tools - save findings, read local docs
Use Cases:
- API documentation research
- Competitive analysis
- Fact-checking reports
- Technical due diligence
Not Included:
- Terminal (prevents accidental local changes)
- Vision/image generation
3. TRIAGE Profile
Purpose: Read-only status checking, issue monitoring, health checks
toolsets: [terminal, file]
tools_enabled: 6
token_estimate: "~2,194 tokens"
token_savings: "~76%"
read_only: true # enforced via prompt
Included Tools:
terminal- curl for Gitea API, status commandsread_file,search_files- log analysis, config inspection
Critical Note on Write Safety:
The file toolset includes write_file and patch. For truly read-only triage, the job prompt MUST include:
[SYSTEM: This is a READ-ONLY triage job. Only use read_file and search_files.
Do NOT use write_file, patch, or terminal commands that modify state.]
Future Enhancement:
Consider adding a disabled_tools parameter to AIAgent for granular control without creating new toolsets.
Use Cases:
- Gitea issue triage
- CI/CD status monitoring
- Log file analysis
- System health checks
4. CREATIVE Profile
Purpose: Content creation, writing, editing
toolsets: [file, web]
tools_enabled: 4
token_estimate: "~1,185 tokens"
token_savings: "~87%"
Included Tools:
read_file,search_files,write_file,patchweb_search,web_extract- references, fact-checking
Use Cases:
- Documentation writing
- Content generation
- Editing and proofreading
- Newsletter/article composition
Not Included:
- Terminal (no system access needed)
- Browser (web_extract sufficient for text)
- Vision/image generation
5. OPS Profile
Purpose: System operations, maintenance, deployment
toolsets: [terminal, process, file]
tools_enabled: 6
token_estimate: "~2,194 tokens"
token_savings: "~76%"
Included Tools:
terminal,process- service management, background tasks- File tools - config editing, log inspection
Use Cases:
- Server maintenance
- Log rotation
- Service restart
- Deployment automation
- Docker container management
How Toolset Filtering Works
The Hermes harness already supports this via AIAgent.__init__:
def __init__(
self,
...
enabled_toolsets: List[str] = None, # Only these toolsets
disabled_toolsets: List[str] = None, # Exclude these toolsets
...
):
The filtering happens in model_tools.get_tool_definitions():
def get_tool_definitions(
enabled_toolsets: List[str] = None,
disabled_toolsets: List[str] = None,
...
) -> List[Dict[str, Any]]:
# 1. Resolve toolsets to tool names via toolsets.resolve_toolset()
# 2. Filter by availability (check_fn for each tool)
# 3. Return OpenAI-format tool definitions
Current Cron Usage (Line 423-443 in cron/scheduler.py):
agent = AIAgent(
model=turn_route["model"],
...
disabled_toolsets=["cronjob", "messaging", "clarify"], # Hardcoded
quiet_mode=True,
platform="cron",
...
)
Wiring into Cron Dispatch
Step 1: Load Profile
import yaml
from pathlib import Path
def load_job_profile(profile_name: str) -> dict:
"""Load a job profile from ~/.timmy/uniwizard/job_profiles.yaml"""
profile_path = Path.home() / ".timmy/uniwizard/job_profiles.yaml"
with open(profile_path) as f:
config = yaml.safe_load(f)
profiles = config.get("profiles", {})
return profiles.get(profile_name, profiles.get("minimal", {"toolsets": ["file"]}))
Step 2: Modify run_job() in cron/scheduler.py
def run_job(job: dict) -> tuple[bool, str, str, Optional[str]]:
...
# Load job profile (default to minimal if not specified)
profile_name = job.get("tool_profile", "minimal")
profile = load_job_profile(profile_name)
# Build toolset filter
enabled_toolsets = profile.get("toolsets", ["file"])
disabled_toolsets = profile.get("disabled_toolsets", ["cronjob", "messaging", "clarify"])
agent = AIAgent(
model=turn_route["model"],
...
enabled_toolsets=enabled_toolsets, # NEW
disabled_toolsets=disabled_toolsets, # MODIFIED
quiet_mode=True,
platform="cron",
...
)
Step 3: Update Job Definition Format
Add tool_profile field to ~/.hermes/cron/jobs.yaml:
jobs:
- id: daily-issue-triage
name: "Triage Gitea Issues"
schedule: "0 9 * * *"
tool_profile: triage # <-- NEW
prompt: "Check timmy-config repo for new issues..."
deliver: telegram
- id: weekly-docs-review
name: "Review Documentation"
schedule: "0 10 * * 1"
tool_profile: creative # <-- NEW
prompt: "Review and improve README files..."
Token Savings Summary
| Profile | Tools | Tokens | Savings |
|---|---|---|---|
Full (all) |
40 | ~9,261 | 0% |
| code-work | 6 | ~2,194 | -76% |
| research | 15 | ~2,518 | -73% |
| triage | 6 | ~2,194 | -76% |
| creative | 4 | ~1,185 | -87% |
| ops | 6 | ~2,194 | -76% |
| minimal | 4 | ~800 | -91% |
Benefits:
- Faster prompt processing (less context to scan)
- Reduced API costs (fewer input tokens)
- More focused tool selection (less confusion)
- Faster tool calls (smaller schema to parse)
Migration Path
Phase 1: Deploy Profiles (This PR)
- Create
~/.timmy/uniwizard/job_profiles.yaml - Create design document
- Post Gitea issue comment
Phase 2: Cron Integration (Next PR)
- Modify
cron/scheduler.pyto load profiles - Add
tool_profilefield to job schema - Update existing jobs to use appropriate profiles
Phase 3: CLI Integration (Future)
- Add
/profileslash command to switch profiles - Show active profile in CLI banner
- Profile-specific skills loading
Files Changed
| File | Purpose |
|---|---|
~/.timmy/uniwizard/job_profiles.yaml |
Profile definitions |
~/.timmy/uniwizard/job_profiles_design.md |
This design document |
Open Questions
-
Should we add
disabled_toolsparameter to AIAgent?- Would enable true read-only triage without prompt hacks
- Requires changes to
model_tools.pyandrun_agent.py
-
Should profiles include model recommendations?
- e.g.,
recommended_model: claude-opus-4for code-work - Could help route simple jobs to cheaper models
- e.g.,
-
Should we support profile composition?
- e.g.,
profiles: [ops, web]for ops jobs that need web lookup
- e.g.,
References
- Hermes toolset system:
~/.hermes/hermes-agent/toolsets.py - Tool filtering logic:
~/.hermes/hermes-agent/model_tools.py:get_tool_definitions() - Cron scheduler:
~/.hermes/hermes-agent/cron/scheduler.py:run_job() - AIAgent initialization:
~/.hermes/hermes-agent/run_agent.py:AIAgent.__init__()