hermes - 💡(How to fix) Fix [i18n] Thai Translation: Developer Guide Part b - context-compression-and-caching, context-engine-plugin, contributing, creating-skills, cron-internals [1 participants]
ON THIS PAGE
Recommended Tools
×6Utilities matched from this issue’s tags and category — try them while you read without losing context.
GitHub issue graph ai analysis
Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.
The report is written in English Markdown for sharing and archival.
Helpful · Quick feedback
Error Message
try: load_dotenv(env_path) except UnicodeDecodeError: load_dotenv(env_path, encoding="latin-1")
Fix Action
Fix / Workaround
กรณีการใช้งานสำหรับ fallback_for_*: สร้าง skill ที่ทำหน้าที่เป็น workaround เมื่อ tool หลักไม่พร้อมใช้งาน ตัวอย่างเช่น skill duckduckgo-search ที่มี fallback_for_tools: [web_search] จะแสดงก็ต่อเมื่อ web search tool (ซึ่งต้องใช้ API key) ไม่ได้ถูกกำหนดค่าไว้
- Module-level override -
_SCRIPT_TIMEOUT(สำหรับ tests/monkeypatching) ใช้เฉพาะเมื่อค่าแตกต่างจากค่าเริ่มต้นเท่านั้น - Environment variable -
HERMES_CRON_SCRIPT_TIMEOUT - Config -
cron.script_timeout_secondsในconfig.yaml(อ่านผ่านload_config()) - Default - 120 seconds
Code Example
context:
engine: "compressor" # default — built-in lossy summarization
engine: "lcm" # example — plugin providing lossless context
---
┌──────────────────────────┐
Incoming message │ Gateway Session Hygiene │ Fires at 85% of context
─────────────────► │ (pre-agent, rough est.) │ Safety net for large sessions
└─────────────┬────────────┘
│
▼
┌──────────────────────────┐
│ Agent ContextCompressor │ Fires at 50% of context (default)
│ (in-loop, real tokens) │ Normal context management
└──────────────────────────┘
---
compression:
enabled: true # Enable/disable compression (default: true)
threshold: 0.50 # Fraction of context window (default: 0.50 = 50%)
target_ratio: 0.20 # How much of threshold to keep as tail (default: 0.20)
protect_last_n: 20 # Minimum protected tail messages (default: 20)
# Summarization model/provider configured under auxiliary:
auxiliary:
compression:
model: null # Override model for summaries (default: auto-detect)
provider: auto # Provider: "auto", "openrouter", "nous", "main", etc.
base_url: null # Custom OpenAI-compatible endpoint
---
context_length = 200,000
threshold_tokens = 200,000 × 0.50 = 100,000
tail_token_budget = 100,000 × 0.20 = 20,000
max_summary_tokens = min(200,000 × 0.05, 12,000) = 10,000
---
[Old tool output cleared to save context space]
---
┌─────────────────────────────────────────────────────────────┐
│ Message list │
│ │
│ [0..2] ← protect_first_n (system + first exchange) │
│ [3..N] ← middle turns → SUMMARIZED │
│ [N..end] ← tail (by token budget OR protect_last_n) │
│ │
└─────────────────────────────────────────────────────────────┘
---
## Goal
[What the user is trying to accomplish]
## Constraints & Preferences
[User preferences, coding style, constraints, important decisions]
## Progress
### Done
[Completed work — specific file paths, commands run, results]
### In Progress
[Work currently underway]
### Blocked
[Any blockers or issues encountered]
## Key Decisions
[Important technical decisions and why]
## Relevant Files
[Files read, modified, or created — with brief note on each]
## Next Steps
[What needs to happen next]
## Critical Context
[Specific values, error messages, configuration details]
---
[0] system: "You are a helpful assistant..." (system prompt)
[1] user: "Help me set up a FastAPI project"
[2] assistant: <tool_call> terminal: mkdir project </tool_call>
[3] tool: "directory created"
[4] assistant: <tool_call> write_file: main.py </tool_call>
[5] tool: "file written (2.3KB)"
... 30 more turns of file editing, testing, debugging ...
[38] assistant: <tool_call> terminal: pytest </tool_call>
[39] tool: "8 passed, 2 failed\n..." (5KB output)
[40] user: "Fix the failing tests"
[41] assistant: <tool_call> read_file: tests/test_api.py </tool_call>
[42] tool: "import pytest\n..." (3KB)
[43] assistant: "I see the issue with the test fixtures..."
[44] user: "Great, also add error handling"
---
[0] system: "You are a helpful assistant...
[Note: Some earlier conversation turns have been compacted...]"
[1] user: "Help me set up a FastAPI project"
[2] assistant: "[CONTEXT COMPACTION] Earlier turns were compacted...
## Goal
Set up a FastAPI project with tests and error handling
## Progress
### Done
- Created project structure: main.py, tests/, requirements.txt
- Implemented 5 API endpoints in main.py
- Wrote 10 test cases in tests/test_api.py
- 8/10 tests passing
### In Progress
- Fixing 2 failing tests (test_create_user, test_delete_user)
## Relevant Files
- main.py — FastAPI app with 5 endpoints
- tests/test_api.py — 10 test cases
- requirements.txt — fastapi, pytest, httpx
## Next Steps
- Fix failing test fixtures
- Add error handling"
[3] user: "Fix the failing tests"
[4] assistant: <tool_call> read_file: tests/test_api.py </tool_call>
[5] tool: "import pytest\n..."
[6] assistant: "I see the issue with the test fixtures..."
[7] user: "Great, also add error handling"
---
Breakpoint 1: System prompt (stable across all turns)
Breakpoint 2: 3rd-to-last non-system message - Rolling window
Breakpoint 3: 2nd-to-last non-system message - Rolling window
Breakpoint 4: Last non-system message - Rolling window
---
# Cache marker format
marker = {"type": "ephemeral"}
# Or for 1-hour TTL:
marker = {"type": "ephemeral", "ttl": "1h"}
---
# config.yaml — TTL สามารถตั้งค่าได้ (ต้องเป็น "5m" หรือ "1h")
prompt_caching:
cache_ttl: "5m"
---
💾 Prompt caching: ENABLED (Claude via OpenRouter, 5m TTL)
---
⚠️ Context is 85% to compaction threshold (42,500/50,000 tokens)
---
# config.yaml
context:
engine: "compressor" # default built-in
engine: "lcm" # activates a plugin engine named "lcm"
---
plugins/context_engine/lcm/
├── __init__.py # exports the ContextEngine subclass
├── plugin.yaml # metadata (name, description, version)
└── ... # any other modules your engine needs
---
from agent.context_engine import ContextEngine
class LCMEngine(ContextEngine):
@property
def name(self) -> str:
"""Short identifier, e.g. 'lcm'. Must match config.yaml value."""
return "lcm"
def update_from_response(self, usage: dict) -> None:
"""Called after every LLM call with the usage dict.
Update self.last_prompt_tokens, self.last_completion_tokens,
self.last_total_tokens from the response.
"""
def should_compress(self, prompt_tokens: int = None) -> bool:
"""Return True if compaction should fire this turn."""
def compress(self, messages: list, current_tokens: int = None) -> list:
"""Compact the message list and return a new (possibly shorter) list.
The returned list must be a valid OpenAI-format message sequence.
"""
---
last_prompt_tokens: int = 0
last_completion_tokens: int = 0
last_total_tokens: int = 0
threshold_tokens: int = 0 # when compression triggers
context_length: int = 0 # model's full context window
compression_count: int = 0 # how many times compress() has run
---
def get_tool_schemas(self):
return [{
"name": "lcm_grep",
"description": "Search the context knowledge graph",
"parameters": {
"type": "object",
"properties": {
"query": {"type": "string", "description": "Search query"}
},
"required": ["query"],
},
}]
def handle_tool_call(self, name, args, **kwargs):
if name == "lcm_grep":
results = self._search_dag(args["query"])
return json.dumps({"results": results})
return json.dumps({"error": f"Unknown tool: {name}"})
---
def register(ctx):
engine = LCMEngine(context_length=200000)
ctx.register_context_engine(engine)
---
1. Engine instantiated (plugin load or directory discovery)
2. on_session_start() — conversation begins
3. update_from_response() — after each API call
4. should_compress() — checked each turn
5. compress() — called when should_compress() returns True
6. on_session_end() — session boundary (CLI exit, /reset, gateway expiry)
---
context:
engine: "lcm" # must match your engine's name property
---
from agent.context_engine import ContextEngine
def test_engine_satisfies_abc():
engine = YourEngine(context_length=200000)
assert isinstance(engine, ContextEngine)
assert engine.name == "your-name"
def test_compress_returns_valid_messages():
engine = YourEngine(context_length=200000)
msgs = [{"role": "user", "content": "hello"}]
result = engine.compress(msgs)
assert isinstance(result, list)
assert all("role" in m for m in result)
---
git clone --recurse-submodules https://github.com/NousResearch/hermes-agent.git
cd hermes-agent
# Create venv with Python 3.11
uv venv venv --python 3.11
export VIRTUAL_ENV="$(pwd)/venv"
# Install with all extras (messaging, cron, CLI menus, dev tools)
uv pip install -e ".[all,dev]"
uv pip install -e "./tinker-atropos"
# Optional: browser tools
npm install
---
mkdir -p ~/.hermes/{cron,sessions,logs,memories,skills}
cp cli-config.yaml.example ~/.hermes/config.yaml
touch ~/.hermes/.env
# Add at minimum an LLM provider key:
echo 'OPENROUTER_API_KEY=sk-or-v1-your-key' >> ~/.hermes/.env
---
# Symlink for global access
mkdir -p ~/.local/bin
ln -sf "$(pwd)/venv/bin/hermes" ~/.local/bin/hermes
# Verify
hermes doctor
hermes chat -q "Hello"
---
pytest tests/ -v
---
try:
from simple_term_menu import TerminalMenu
menu = TerminalMenu(options)
idx = menu.show()
except (ImportError, NotImplementedError):
# Fallback: numbered menu
for i, opt in enumerate(options):
print(f" {i+1}. {opt}")
idx = int(input("Choice: ")) - 1
---
try:
load_dotenv(env_path)
except UnicodeDecodeError:
load_dotenv(env_path, encoding="latin-1")
---
import platform
if platform.system() != "Windows":
kwargs["preexec_fn"] = os.setsid
---
fix/description # Bug fixes
feat/description # New features
docs/description # Documentation
test/description # Tests
refactor/description # Code restructuring
---
<type>(<scope>): <description>
---
fix(cli): prevent crash in save_config_value when model is a string
feat(gateway): add WhatsApp multi-user session isolation
fix(security): prevent shell injection in sudo password piping
---
skills/
├── research/
│ └── arxiv/
│ ├── SKILL.md # Required: main instructions
│ └── scripts/ # Optional: helper scripts
│ └── search_arxiv.py
├── productivity/
│ └── ocr-and-documents/
│ ├── SKILL.md
│ ├── scripts/
│ └── references/
└── ...
---
---
name: my-skill
description: Brief description (shown in skill search results)
version: 1.0.0
author: Your Name
license: MIT
platforms: [macos, linux] # Optional - restrict to specific OS platforms
# Valid: macos, linux, windows
# Omit to load on all platforms (default)
metadata:
hermes:
tags: [Category, Subcategory, Keywords]
related_skills: [other-skill-name]
requires_toolsets: [web] # Optional - only show when these toolsets are active
requires_tools: [web_search] # Optional - only show when these tools are available
fallback_for_toolsets: [browser] # Optional - hide when these toolsets are active
fallback_for_tools: [browser_navigate] # Optional - hide when these tools exist
config: # Optional - config.yaml settings the skill needs
- key: my.setting
description: "What this setting controls"
default: "sensible-default"
prompt: "Display prompt for setup"
required_environment_variables: # Optional - env vars the skill needs
- name: MY_API_KEY
prompt: "Enter your API key"
help: "Get one at https://example.com"
required_for: "API access"
---
# Skill Title
Brief intro.
## When to Use
Trigger conditions - when should the agent load this skill?
## Quick Reference
Table of common commands or API calls.
## Procedure
Step-by-step instructions the agent follows.
## Pitfalls
Known failure modes and how to handle them.
## Verification
How the agent confirms it worked.
---
platforms: [macos] # macOS เท่านั้น (เช่น iMessage, Apple Reminders)
platforms: [macos, linux] # macOS และ Linux
platforms: [windows] # Windows เท่านั้น
---
metadata:
hermes:
requires_toolsets: [web] # ซ่อนหาก web toolset ไม่ทำงาน
requires_tools: [web_search] # ซ่อนหาก web_search tool ไม่พร้อมใช้งาน
fallback_for_toolsets: [browser] # ซ่อนหาก browser toolset ทำงานอยู่
fallback_for_tools: [browser_navigate] # ซ่อนหาก browser_navigate มีอยู่
---
required_environment_variables:
- name: TENOR_API_KEY
prompt: "Tenor API key" # แสดงเมื่อถามผู้ใช้
help: "Get your key at https://tenor.com" # ข้อความช่วยเหลือหรือ URL
required_for: "GIF search functionality" # สิ่งที่ต้องการตัวแปรนี้
---
terminal:
env_passthrough:
- MY_CUSTOM_VAR
- ANOTHER_VAR
---
required_environment_variables:
- name: TENOR_API_KEY
prompt: Tenor API key
help: Get a key from https://developers.google.com/tenor
required_for: full functionality
---
metadata:
hermes:
config:
- key: myplugin.path
description: Path to the plugin data directory
default: "~/myplugin-data"
prompt: Plugin data directory path
- key: myplugin.domain
description: Domain the plugin operates on
default: ""
prompt: Plugin domain (e.g., AI/ML research)
---
skills:
config:
myplugin:
path: ~/my-data
---
[Skill config (from ~/.hermes/config.yaml):
myplugin.path = /home/user/my-data
]
---
hermes config set skills.config.myplugin.path ~/my-data
---
required_credential_files:
- path: google_token.json
description: Google OAuth2 token (created by setup script)
- path: google_client_secret.json
description: Google OAuth2 client credentials
---
To analyse the input, run:
node ${HERMES_SKILL_DIR}/scripts/analyse.js <input>
---
Current date: !`date -u +%Y-%m-%d`
Git branch: !`git -C ${HERMES_SKILL_DIR} rev-parse --abbrev-ref HEAD`
---
# config.yaml
skills:
inline_shell: true
inline_shell_timeout: 10 # seconds per snippet
---
hermes chat --toolsets skills -q "Use the X skill to do Y"
---
hermes skills publish skills/my-skill --to github --repo owner/repo
---
hermes skills tap add owner/repo
---
{
"id": "a1b2c3d4e5f6",
"name": "Daily briefing",
"prompt": "Summarize today's AI news and funding rounds",
"schedule": {
"kind": "cron",
"expr": "0 9 * * *",
"display": "0 9 * * *"
},
"skills": ["ai-funding-daily-report"],
"deliver": "telegram:-1001234567890",
"repeat": {
"times": null,
"completed": 42
},
"state": "scheduled",
"enabled": true,
"next_run_at": "2025-01-16T09:00:00Z",
"last_run_at": "2025-01-15T09:00:00Z",
"last_status": "ok",
"created_at": "2025-01-01T00:00:00Z",
"model": null,
"provider": null,
"script": null
}
---
tick()
1. Acquire scheduler lock (prevents overlapping ticks)
2. Load all jobs from jobs.json
3. Filter to due jobs (next_run <= now AND state == "scheduled")
4. For each due job:
a. Set state to "running"
b. Create fresh AIAgent session (no conversation history)
c. Load attached skills in order (injected as user messages)
d. Run the job prompt through the agent
e. Deliver the response to the configured target
f. Update run_count, compute next_run
g. If repeat count exhausted → state = "completed"
h. Otherwise → state = "scheduled"
5. Write updated jobs back to jobs.json
6. Release scheduler lock
---
Create a daily funding report → attach "ai-funding-daily-report" skill
---
# ~/.hermes/scripts/check_competitors.py
import requests, json
# Fetch competitor release notes, diff against last run
# Print summary to stdout - agent analyzes and reports
---
hermes cron list # Show all jobs
hermes cron create # Interactive job creation (alias: add)
hermes cron edit <job_id> # Edit job configuration
hermes cron pause <job_id> # Pause a running job
hermes cron resume <job_id> # Resume a paused job
hermes cron run <job_id> # Trigger immediate execution
hermes cron remove <job_id> # Delete a jobRAW_BUFFERClick to expand / collapse
📄 developer-guide/context-compression-and-caching.md
Context Compression and Caching
Hermes Agent ใช้ระบบการบีบอัดแบบคู่ (dual compression system) และการแคช prompt ของ Anthropic เพื่อจัดการการใช้ context window อย่างมีประสิทธิภาพตลอดการสนทนาที่ยาวนาน
Source files: agent/context_engine.py (ABC), agent/context_compressor.py (default engine),
agent/prompt_caching.py, gateway/run.py (session hygiene), run_agent.py (search for _compress_context)
Pluggable Context Engine
การจัดการ Context ถูกสร้างขึ้นบน ContextEngine ABC (agent/context_engine.py) โดย ContextCompressor ที่ติดตั้งมาให้เป็น implementation เริ่มต้น แต่สามารถใช้ปลั๊กอินอื่นมาแทนที่ได้ (เช่น Lossless Context Management)
context:
engine: "compressor" # default — built-in lossy summarization
engine: "lcm" # example — plugin providing lossless contextEngine นี้มีหน้าที่รับผิดชอบในส่วนต่างๆ ดังนี้:
- การตัดสินใจว่าเมื่อใดที่ควรทำการบีบอัด (
should_compress()) - การดำเนินการบีบอัด (
compress()) - การเปิดเผยเครื่องมือ (tools) ที่ Agent สามารถเรียกใช้ได้ตามความจำเป็น (เช่น
lcm_grep) - การติดตามการใช้ token จาก API responses
การเลือกใช้ Engine ถูกกำหนดผ่าน context.engine ใน config.yaml ลำดับการตรวจสอบมีดังนี้:
- ตรวจสอบไดเรกทอรี
plugins/context_engine/<name>/ - ตรวจสอบระบบปลั๊กอินทั่วไป (
register_context_engine()) - ย้อนกลับไปใช้
ContextCompressorที่ติดตั้งมาให้
Plugin engines จะไม่ถูกเปิดใช้งานโดยอัตโนมัติ - ผู้ใช้ต้องตั้งค่า context.engine ให้เป็นชื่อของ plugin อย่างชัดเจน ค่าเริ่มต้น "compressor" จะใช้ตัวที่ติดตั้งมาให้เสมอ
สามารถตั้งค่าได้ผ่าน hermes plugins → Provider Plugins → Context Engine หรือแก้ไข config.yaml โดยตรง
หากต้องการสร้าง plugin context engine ให้ดูที่ Context Engine Plugins
Dual Compression System
Hermes มีชั้นการบีบอัดที่แยกจากกันสองชั้น ซึ่งทำงานอย่างอิสระ:
┌──────────────────────────┐
Incoming message │ Gateway Session Hygiene │ Fires at 85% of context
─────────────────► │ (pre-agent, rough est.) │ Safety net for large sessions
└─────────────┬────────────┘
│
▼
┌──────────────────────────┐
│ Agent ContextCompressor │ Fires at 50% of context (default)
│ (in-loop, real tokens) │ Normal context management
└──────────────────────────┘1. Gateway Session Hygiene (85% threshold)
อยู่ใน gateway/run.py (ค้นหา Session hygiene: auto-compress) นี่คือ safety net ที่จะทำงาน
ก่อนที่ Agent จะประมวลผลข้อความ เป็นการป้องกัน API failures เมื่อ session
มีขนาดใหญ่เกินไประหว่าง turn ต่างๆ (เช่น การสะสมข้อมูลข้ามคืนใน Telegram/Discord)
- Threshold: กำหนดไว้ที่ 85% ของความยาว context ของ model
- Token source: ให้ความสำคัญกับ token ที่รายงานโดย API จริงจาก turn ล่าสุด; หากไม่สามารถทำได้จะย้อนกลับไปใช้การประมาณค่าแบบ rough character-based estimate (
estimate_messages_tokens_rough) - Fires: ทำงานเฉพาะเมื่อ
len(history) >= 4และเปิดใช้งานการบีบอัด - Purpose: ดักจับ session ที่หลุดรอดจาก compressor ของ Agent เอง
Threshold ของ gateway hygiene ถูกตั้งให้สูงกว่า compressor ของ Agent โดยเจตนา การตั้งค่าไว้ที่ 50% (เท่ากับ Agent) ทำให้เกิดการบีบอัดก่อนเวลาอันควรในทุก turn ใน session gateway ที่ยาวนาน
2. Agent ContextCompressor (50% threshold, configurable)
อยู่ใน agent/context_compressor.py นี่คือ ระบบการบีบอัดหลัก
ที่ทำงานภายใน tool loop ของ Agent โดยเข้าถึงจำนวน token ที่แม่นยำ
ซึ่งรายงานโดย API
Configuration
การตั้งค่าการบีบอัดทั้งหมดจะถูกอ่านจาก config.yaml ภายใต้คีย์ compression:
compression:
enabled: true # Enable/disable compression (default: true)
threshold: 0.50 # Fraction of context window (default: 0.50 = 50%)
target_ratio: 0.20 # How much of threshold to keep as tail (default: 0.20)
protect_last_n: 20 # Minimum protected tail messages (default: 20)
# Summarization model/provider configured under auxiliary:
auxiliary:
compression:
model: null # Override model for summaries (default: auto-detect)
provider: auto # Provider: "auto", "openrouter", "nous", "main", etc.
base_url: null # Custom OpenAI-compatible endpointParameter Details
| Parameter | Default | Range | Description |
|---|---|---|---|
threshold | 0.50 | 0.0-1.0 | Compression triggers when prompt tokens ≥ threshold × context_length |
target_ratio | 0.20 | 0.10-0.80 | Controls tail protection token budget: threshold_tokens × target_ratio |
protect_last_n | 20 | ≥1 | Minimum number of recent messages always preserved |
protect_first_n | 3 | (hardcoded) | System prompt + first exchange always preserved |
Computed Values (for a 200K context model at defaults)
context_length = 200,000
threshold_tokens = 200,000 × 0.50 = 100,000
tail_token_budget = 100,000 × 0.20 = 20,000
max_summary_tokens = min(200,000 × 0.05, 12,000) = 10,000Compression Algorithm
เมธอด ContextCompressor.compress() ทำงานตาม algorithm 4 เฟส:
Phase 1: Prune Old Tool Results (cheap, no LLM call)
ผลลัพธ์ของ tool เก่า (>200 chars) ที่อยู่นอก protected tail จะถูกแทนที่ด้วย:
[Old tool output cleared to save context space]นี่คือ pre-pass ที่ประหยัดค่าใช้จ่าย ซึ่งช่วยประหยัด token จำนวนมากจาก tool outputs ที่มีรายละเอียดมาก (เช่น file contents, terminal output, search results)
Phase 2: Determine Boundaries
┌─────────────────────────────────────────────────────────────┐
│ Message list │
│ │
│ [0..2] ← protect_first_n (system + first exchange) │
│ [3..N] ← middle turns → SUMMARIZED │
│ [N..end] ← tail (by token budget OR protect_last_n) │
│ │
└─────────────────────────────────────────────────────────────┘การปกป้อง tail เป็นแบบ token-budget based: จะเดินย้อนกลับจากส่วนท้าย (end)
และสะสม token จนกว่าจะใช้ budget หมด หาก budget นั้นปกป้องจำนวนข้อความน้อยกว่าที่กำหนด จะย้อนกลับไปใช้ค่า protect_last_n ที่กำหนดไว้
Boundaries ถูกจัดเรียงให้หลีกเลี่ยงการแบ่งกลุ่ม tool_call/tool_result
เมธอด _align_boundary_backward() จะเดินผ่าน tool results ที่ต่อเนื่องกัน
เพื่อค้นหาข้อความ assistant ตัวแม่ (parent assistant message) โดยคงกลุ่มไว้ครบถ้วน
Phase 3: Generate Structured Summary
:::warning Summary model context length
Summary model ต้องมี context window ที่ ใหญ่กว่าหรือเท่ากับ main agent model.
ส่วนกลางทั้งหมดจะถูกส่งไปยัง summary model ในการเรียก call_llm(task="compression") เพียงครั้งเดียว หาก context ของ summary model มีขนาดเล็กกว่า API จะส่งข้อผิดพลาด context-length กลับมา — _generate_summary() จะดักจับข้อผิดพลาดนี้, บันทึก warning, และส่งค่า None กลับมา Compressor จะทำการลบ middle turns โดยไม่มี summary ทำให้ context การสนทนาสูญหายไปอย่างเงียบๆ นี่คือสาเหตุที่พบบ่อยที่สุดที่ทำให้คุณภาพการบีบอัดลดลง
:::
Middle turns จะถูกสรุปโดยใช้ auxiliary LLM ด้วย structured template:
## Goal
[What the user is trying to accomplish]
## Constraints & Preferences
[User preferences, coding style, constraints, important decisions]
## Progress
### Done
[Completed work — specific file paths, commands run, results]
### In Progress
[Work currently underway]
### Blocked
[Any blockers or issues encountered]
## Key Decisions
[Important technical decisions and why]
## Relevant Files
[Files read, modified, or created — with brief note on each]
## Next Steps
[What needs to happen next]
## Critical Context
[Specific values, error messages, configuration details]Summary budget จะปรับขนาดตามปริมาณ content ที่กำลังถูกบีบอัด:
- Formula:
content_tokens × 0.20(ค่าคงที่_SUMMARY_RATIO) - Minimum: 2,000 tokens
- Maximum:
min(context_length × 0.05, 12,000)tokens
Phase 4: Assemble Compressed Messages
รายการข้อความที่ถูกบีบอัดประกอบด้วย:
- Head messages (พร้อมหมายเหตุที่เพิ่มเข้าไปใน system prompt ในการบีบอัดครั้งแรก)
- Summary message (เลือก role เพื่อหลีกเลี่ยงการละเมิด role เดียวกันติดต่อกัน)
- Tail messages (ไม่ถูกแก้ไข)
คู่ tool_call/tool_result ที่หลงเหลือ (Orphaned) จะถูกทำความสะอาดโดย _sanitize_tool_pairs():
- Tool results ที่อ้างถึง calls ที่ถูกลบ → ถูกลบออก
- Tool calls ที่ผลลัพธ์ถูกลบ → ถูกแทรก stub result เข้าไป
Iterative Re-compression
ในการบีบอัดครั้งถัดไป จะมีการส่ง summary ก่อนหน้าไปยัง LLM พร้อมคำแนะนำให้ อัปเดต แทนการสรุปใหม่ทั้งหมด วิธีนี้ช่วยรักษาข้อมูลข้ามการบีบอัดหลายครั้ง — รายการจะย้ายจาก "In Progress" ไป "Done", มี progress ใหม่ถูกเพิ่มเข้ามา, และข้อมูลที่ล้าสมัยจะถูกลบออก
ฟิลด์ _previous_summary บน compressor instance จะเก็บข้อความ summary ล่าสุดไว้เพื่อวัตถุประสงค์นี้
Before/After Example
Before Compression (45 messages, ~95K tokens)
[0] system: "You are a helpful assistant..." (system prompt)
[1] user: "Help me set up a FastAPI project"
[2] assistant: <tool_call> terminal: mkdir project </tool_call>
[3] tool: "directory created"
[4] assistant: <tool_call> write_file: main.py </tool_call>
[5] tool: "file written (2.3KB)"
... 30 more turns of file editing, testing, debugging ...
[38] assistant: <tool_call> terminal: pytest </tool_call>
[39] tool: "8 passed, 2 failed\n..." (5KB output)
[40] user: "Fix the failing tests"
[41] assistant: <tool_call> read_file: tests/test_api.py </tool_call>
[42] tool: "import pytest\n..." (3KB)
[43] assistant: "I see the issue with the test fixtures..."
[44] user: "Great, also add error handling"After Compression (25 messages, ~45K tokens)
[0] system: "You are a helpful assistant...
[Note: Some earlier conversation turns have been compacted...]"
[1] user: "Help me set up a FastAPI project"
[2] assistant: "[CONTEXT COMPACTION] Earlier turns were compacted...
## Goal
Set up a FastAPI project with tests and error handling
## Progress
### Done
- Created project structure: main.py, tests/, requirements.txt
- Implemented 5 API endpoints in main.py
- Wrote 10 test cases in tests/test_api.py
- 8/10 tests passing
### In Progress
- Fixing 2 failing tests (test_create_user, test_delete_user)
## Relevant Files
- main.py — FastAPI app with 5 endpoints
- tests/test_api.py — 10 test cases
- requirements.txt — fastapi, pytest, httpx
## Next Steps
- Fix failing test fixtures
- Add error handling"
[3] user: "Fix the failing tests"
[4] assistant: <tool_call> read_file: tests/test_api.py </tool_call>
[5] tool: "import pytest\n..."
[6] assistant: "I see the issue with the test fixtures..."
[7] user: "Great, also add error handling"Prompt Caching (Anthropic)
Source: agent/prompt_caching.py
ลดต้นทุน token input ลงประมาณ 75% ในการสนทนาหลาย turn โดยการแคช prefix ของการสนทนา ใช้ cache_control breakpoints ของ Anthropic
Strategy: system_and_3
Anthropic อนุญาตให้มี cache_control breakpoints ได้สูงสุด 4 จุดต่อ request Hermes ใช้กลยุทธ์ "system_and_3":
Breakpoint 1: System prompt (stable across all turns)
Breakpoint 2: 3rd-to-last non-system message - Rolling window
Breakpoint 3: 2nd-to-last non-system message - Rolling window
Breakpoint 4: Last non-system message - Rolling windowHow It Works
apply_anthropic_cache_control() จะ deep-copy messages และแทรก marker cache_control:
# Cache marker format
marker = {"type": "ephemeral"}
# Or for 1-hour TTL:
marker = {"type": "ephemeral", "ttl": "1h"}การใช้ marker จะแตกต่างกันไปตาม content type:
| Content Type | Where Marker Goes |
|---|---|
| String content | ถูกแปลงเป็น [{"type": "text", "text": ..., "cache_control": ...}] |
| List content | ถูกเพิ่มเข้าไปใน dict ของ element ล่าสุด |
| None/empty | ถูกเพิ่มเป็น msg["cache_control"] |
| Tool messages | ถูกเพิ่มเป็น msg["cache_control"] (สำหรับ Anthropic เท่านั้น) |
Cache-Aware Design Patterns
-
Stable system prompt: system prompt คือ breakpoint 1 และถูกแคชตลอดทุก turn หลีกเลี่ยงการแก้ไขมันกลางการสนทนา (compression จะเพิ่ม note เฉพาะในการบีบอัดครั้งแรก)
-
Message ordering matters: Cache hits ต้องการการจับคู่ prefix การเพิ่มหรือลบ messages ตรงกลางจะทำให้ cache สำหรับทุกอย่างที่ตามมาเป็นโมฆะ
-
Compression cache interaction: หลังจากการบีบอัด cache จะเป็นโมฆะสำหรับ region ที่ถูกบีบอัด แต่ cache ของ system prompt ยังคงอยู่ หน้าต่าง 3 messages แบบ rolling จะสร้างการแคชขึ้นมาใหม่ภายใน 1-2 turns
-
TTL selection: ค่าเริ่มต้นคือ
5m(5 นาที) ควรใช้1hสำหรับ session ที่ยาวนานซึ่งผู้ใช้มีการพักระหว่าง turn
Enabling Prompt Caching
Prompt caching จะเปิดใช้งานโดยอัตโนมัติเมื่อ:
- Model เป็น Anthropic Claude model (ตรวจพบจากชื่อ model)
- Provider รองรับ
cache_control(native Anthropic API หรือ OpenRouter)
# config.yaml — TTL สามารถตั้งค่าได้ (ต้องเป็น "5m" หรือ "1h")
prompt_caching:
cache_ttl: "5m"CLI จะแสดงสถานะการแคชเมื่อเริ่มต้น:
💾 Prompt caching: ENABLED (Claude via OpenRouter, 5m TTL)Context Pressure Warnings
Agent จะปล่อย context pressure warnings เมื่อถึง 85% ของ threshold การบีบอัด (ไม่ใช่ 85% ของ context — แต่เป็น 85% ของ threshold ซึ่งตัวมันเองคือ 50% ของ context):
⚠️ Context is 85% to compaction threshold (42,500/50,000 tokens)หลังจากการบีบอัด หากการใช้งานลดลงต่ำกว่า 85% ของ threshold สถานะ warning จะถูกเคลียร์ หากการบีบอัดไม่สามารถลดให้ต่ำกว่าระดับ warning ได้ (เพราะการสนทนามีความหนาแน่นเกินไป) warning จะยังคงอยู่ แต่การบีบอัดจะไม่ทำงานจนกว่าจะเกิน threshold อีกครั้ง
📄 developer-guide/context-engine-plugin.md
sidebar_position: 9 title: "Context Engine Plugins" description: "How to build a context engine plugin that replaces the built-in ContextCompressor"
การสร้าง Context Engine Plugin
Context engine plugins ใช้แทนที่ ContextCompressor ที่มีมาให้ในตัว ด้วยกลยุทธ์ทางเลือกสำหรับการจัดการบริบทการสนทนา ตัวอย่างเช่น engine สำหรับ Lossless Context Management (LCM) ที่สร้าง knowledge DAG แทนการสรุปแบบสูญเสียข้อมูล (lossy summarization).
วิธีการทำงาน
การจัดการบริบทของ agent ถูกสร้างขึ้นบน ContextEngine ABC (agent/context_engine.py) ContextCompressor ที่มีมาให้ในตัวคือการใช้งานค่าเริ่มต้น (default implementation) Plugin engines ต้องใช้งาน interface เดียวกัน
สามารถมี context engine ที่ทำงานได้เพียง หนึ่ง ตัวเท่านั้น การเลือกขึ้นอยู่กับการกำหนดค่า (config-driven):
# config.yaml
context:
engine: "compressor" # default built-in
engine: "lcm" # activates a plugin engine named "lcm"Plugin engines จะ ไม่ถูกเปิดใช้งานโดยอัตโนมัติ - ผู้ใช้ต้องกำหนดค่า context.engine ให้เป็นชื่อของ plugin อย่างชัดเจน
โครงสร้าง Directory
Context engine แต่ละตัวจะอยู่ใน plugins/context_engine/<name>/:
plugins/context_engine/lcm/
├── __init__.py # exports the ContextEngine subclass
├── plugin.yaml # metadata (name, description, version)
└── ... # any other modules your engine needsContextEngine ABC
Engine ของคุณต้องใช้งาน method ที่จำเป็น เหล่านี้:
from agent.context_engine import ContextEngine
class LCMEngine(ContextEngine):
@property
def name(self) -> str:
"""Short identifier, e.g. 'lcm'. Must match config.yaml value."""
return "lcm"
def update_from_response(self, usage: dict) -> None:
"""Called after every LLM call with the usage dict.
Update self.last_prompt_tokens, self.last_completion_tokens,
self.last_total_tokens from the response.
"""
def should_compress(self, prompt_tokens: int = None) -> bool:
"""Return True if compaction should fire this turn."""
def compress(self, messages: list, current_tokens: int = None) -> list:
"""Compact the message list and return a new (possibly shorter) list.
The returned list must be a valid OpenAI-format message sequence.
"""คุณสมบัติคลาส (Class attributes) ที่ engine ของคุณต้องดูแลรักษา
agent จะอ่านค่าเหล่านี้โดยตรงสำหรับการแสดงผลและการบันทึก log:
last_prompt_tokens: int = 0
last_completion_tokens: int = 0
last_total_tokens: int = 0
threshold_tokens: int = 0 # when compression triggers
context_length: int = 0 # model's full context window
compression_count: int = 0 # how many times compress() has runmethod ทางเลือก
method เหล่านี้มีค่าเริ่มต้นที่เหมาะสมใน ABC สามารถเขียนทับได้ตามความจำเป็น:
| Method | Default | Override when |
|---|---|---|
on_session_start(session_id, **kwargs) | No-op | คุณจำเป็นต้องโหลดสถานะที่ถูกบันทึกไว้ (DAG, DB) |
on_session_end(session_id, messages) | No-op | คุณจำเป็นต้อง flush state, close connections |
on_session_reset() | Resets token counters | คุณมีสถานะเฉพาะ session ที่ต้องล้าง |
update_model(model, context_length, ...) | Updates context_length + threshold | คุณจำเป็นต้องคำนวณงบประมาณใหม่เมื่อเปลี่ยน model |
get_tool_schemas() | Returns [] | engine ของคุณมี tools ที่ agent เรียกใช้ได้ (เช่น lcm_grep) |
handle_tool_call(name, args, **kwargs) | Returns error JSON | คุณใช้งาน tool handlers |
should_compress_preflight(messages) | Returns False | คุณสามารถทำ estimate ก่อนเรียก API ที่มีค่าใช้จ่ายต่ำได้ |
get_status() | Standard token/threshold dict | คุณมี metrics ที่กำหนดเองที่ต้องการเปิดเผย |
Engine tools
Context engines สามารถเปิดเผย tools ที่ agent เรียกใช้ได้โดยตรง ให้ return schemas จาก get_tool_schemas() และจัดการการเรียกใช้ใน handle_tool_call():
def get_tool_schemas(self):
return [{
"name": "lcm_grep",
"description": "Search the context knowledge graph",
"parameters": {
"type": "object",
"properties": {
"query": {"type": "string", "description": "Search query"}
},
"required": ["query"],
},
}]
def handle_tool_call(self, name, args, **kwargs):
if name == "lcm_grep":
results = self._search_dag(args["query"])
return json.dumps({"results": results})
return json.dumps({"error": f"Unknown tool: {name}"})Engine tools จะถูกแทรกเข้าไปในรายการ tools ของ agent เมื่อเริ่มต้น และถูกส่งออกไปโดยอัตโนมัติ - ไม่จำเป็นต้องลงทะเบียนใน registry
การลงทะเบียน (Registration)
ผ่าน directory (แนะนำ)
วาง engine ของคุณใน plugins/context_engine/<name>/ ไฟล์ __init__.py ต้อง export ContextEngine subclass ระบบ discovery จะค้นหาและสร้าง instance ให้โดยอัตโนมัติ
ผ่าน general plugin system
general plugin สามารถลงทะเบียน context engine ได้เช่นกัน:
def register(ctx):
engine = LCMEngine(context_length=200000)
ctx.register_context_engine(engine)สามารถลงทะเบียน engine ได้เพียงตัวเดียว หาก plugin ตัวที่สองพยายามลงทะเบียน จะถูกปฏิเสธพร้อมคำเตือน
วงจรชีวิต (Lifecycle)
1. Engine instantiated (plugin load or directory discovery)
2. on_session_start() — conversation begins
3. update_from_response() — after each API call
4. should_compress() — checked each turn
5. compress() — called when should_compress() returns True
6. on_session_end() — session boundary (CLI exit, /reset, gateway expiry)on_session_reset() ถูกเรียกใช้เมื่อใช้ /new หรือ /reset เพื่อล้างสถานะเฉพาะ session โดยไม่จำเป็นต้องปิดระบบทั้งหมด
การกำหนดค่า (Configuration)
ผู้ใช้สามารถเลือก engine ของคุณผ่าน hermes plugins → Provider Plugins → Context Engine หรือโดยการแก้ไข config.yaml:
context:
engine: "lcm" # must match your engine's name propertyบล็อก config compression (compression.threshold, compression.protect_last_n, ฯลฯ) เป็นของ ContextCompressor ที่มีมาให้ในตัวโดยเฉพาะ Engine ของคุณควรกำหนดรูปแบบ config ของตัวเองหากจำเป็น โดยอ่านค่าจาก config.yaml ในระหว่างการเริ่มต้น (initialization)
การทดสอบ (Testing)
from agent.context_engine import ContextEngine
def test_engine_satisfies_abc():
engine = YourEngine(context_length=200000)
assert isinstance(engine, ContextEngine)
assert engine.name == "your-name"
def test_compress_returns_valid_messages():
engine = YourEngine(context_length=200000)
msgs = [{"role": "user", "content": "hello"}]
result = engine.compress(msgs)
assert isinstance(result, list)
assert all("role" in m for m in result)ดูที่ tests/agent/test_context_engine.py สำหรับชุดการทดสอบสัญญา ABC ฉบับเต็ม
ดูเพิ่มเติม (See also)
- Context Compression and Caching - วิธีการทำงานของ compressor ที่มีมาให้ในตัว
- Memory Provider Plugins - ระบบ plugin แบบเลือกตัวเดียวที่คล้ายกันสำหรับ memory
- Plugins - ภาพรวมของระบบ plugin ทั่วไป
📄 developer-guide/contributing.md
sidebar_position: 4 title: "Contributing" description: "How to contribute to Hermes Agent - dev setup, code style, PR process"
การมีส่วนร่วม (Contributing)
ขอขอบคุณสำหรับการมีส่วนร่วมใน Hermes Agent! คู่มือนี้ครอบคลุมตั้งแต่การตั้งค่าสภาพแวดล้อมสำหรับนักพัฒนา การทำความเข้าใจ codebase และขั้นตอนการรวม PR ของคุณ
ลำดับความสำคัญของการมีส่วนร่วม (Contribution Priorities)
เราให้ความสำคัญกับการมีส่วนร่วมตามลำดับนี้:
- การแก้ไขบั๊ก (Bug fixes) - เช่น การล่ม (crashes), พฤติกรรมที่ไม่ถูกต้อง, การสูญหายของข้อมูล
- ความเข้ากันได้ข้ามแพลตฟอร์ม (Cross-platform compatibility) - เช่น macOS, Linux distros ต่างๆ, WSL2
- การเสริมความแข็งแกร่งด้านความปลอดภัย (Security hardening) - เช่น shell injection, prompt injection, path traversal
- ประสิทธิภาพและความทนทาน (Performance and robustness) - เช่น retry logic, error handling, graceful degradation
- ทักษะใหม่ (New skills) - ที่มีประโยชน์ในวงกว้าง (ดูที่ Creating Skills)
- เครื่องมือใหม่ (New tools) - ที่ไม่ค่อยจำเป็น; ความสามารถส่วนใหญ่ควรอยู่ในรูปแบบของ skills
- เอกสาร (Documentation) - การแก้ไข, การชี้แจง, ตัวอย่างใหม่
เส้นทางในการมีส่วนร่วมทั่วไป (Common contribution paths)
- ต้องการสร้างเครื่องมือใหม่ใช่หรือไม่? เริ่มต้นที่ Adding Tools
- ต้องการสร้าง skill ใหม่ใช่หรือไม่? เริ่มต้นที่ Creating Skills
- ต้องการสร้าง inference provider ใหม่ใช่หรือไม่? เริ่มต้นที่ Adding Providers
การตั้งค่าสำหรับนักพัฒนา (Development Setup)
สิ่งที่ต้องมี (Prerequisites)
| Requirement | Notes |
|---|---|
| Git | ต้องรองรับ --recurse-submodules และติดตั้งส่วนขยาย git-lfs |
| Python 3.11+ | uv จะติดตั้งให้หากขาดไป |
| uv | ตัวจัดการ package Python ที่รวดเร็ว (install) |
| Node.js 20+ | ทางเลือก - จำเป็นสำหรับ browser tools และ WhatsApp bridge (ต้องตรงกับ engines ใน root package.json) |
Clone และ ติดตั้ง (Clone and Install)
git clone --recurse-submodules https://github.com/NousResearch/hermes-agent.git
cd hermes-agent
# Create venv with Python 3.11
uv venv venv --python 3.11
export VIRTUAL_ENV="$(pwd)/venv"
# Install with all extras (messaging, cron, CLI menus, dev tools)
uv pip install -e ".[all,dev]"
uv pip install -e "./tinker-atropos"
# Optional: browser tools
npm installกำหนดค่าสำหรับการพัฒนา (Configure for Development)
mkdir -p ~/.hermes/{cron,sessions,logs,memories,skills}
cp cli-config.yaml.example ~/.hermes/config.yaml
touch ~/.hermes/.env
# Add at minimum an LLM provider key:
echo 'OPENROUTER_API_KEY=sk-or-v1-your-key' >> ~/.hermes/.envรัน (Run)
# Symlink for global access
mkdir -p ~/.local/bin
ln -sf "$(pwd)/venv/bin/hermes" ~/.local/bin/hermes
# Verify
hermes doctor
hermes chat -q "Hello"รัน Tests (Run Tests)
pytest tests/ -vCode Style
- PEP 8 พร้อมข้อยกเว้นในทางปฏิบัติ (ไม่บังคับความยาวบรรทัดที่เข้มงวด)
- Comments: เฉพาะเมื่ออธิบายเจตนาที่ไม่ได้ชัดเจน, trade-offs, หรือความแปลกของ API
- Error handling: ดักจับ exceptions เฉพาะเจาะจง ใช้
logger.warning()/logger.error()พร้อมexc_info=Trueสำหรับข้อผิดพลาดที่ไม่คาดคิด - Cross-platform: ห้ามสมมติว่าเป็น Unix (ดูด้านล่าง)
- Profile-safe paths: ห้าม hardcode
~/.hermes- ให้ใช้get_hermes_home()จากhermes_constantsสำหรับ code paths และdisplay_hermes_home()สำหรับข้อความที่แสดงต่อผู้ใช้ ดู AGENTS.md สำหรับกฎทั้งหมด
ความเข้ากันได้ข้ามแพลตฟอร์ม (Cross-Platform Compatibility)
Hermes รองรับ Linux, macOS, และ WSL2 อย่างเป็นทางการ ไม่รองรับ Windows แบบ Native แต่ codebase มีรูปแบบการเขียนโค้ดป้องกันบางอย่างเพื่อหลีกเลี่ยงการล่มอย่างรุนแรงในกรณีขอบเขต (edge cases) กฎหลัก:
1. termios และ fcntl ใช้ได้เฉพาะบน Unix เท่านั้น
ต้องดักจับทั้ง ImportError และ NotImplementedError เสมอ:
try:
from simple_term_menu import TerminalMenu
menu = TerminalMenu(options)
idx = menu.show()
except (ImportError, NotImplementedError):
# Fallback: numbered menu
for i, opt in enumerate(options):
print(f" {i+1}. {opt}")
idx = int(input("Choice: ")) - 12. File encoding
สภาพแวดล้อมบางแห่งอาจบันทึกไฟล์ .env ด้วย encoding ที่ไม่ใช่ UTF-8:
try:
load_dotenv(env_path)
except UnicodeDecodeError:
load_dotenv(env_path, encoding="latin-1")3. Process management
os.setsid(), os.killpg(), และ signal handling แตกต่างกันไปในแต่ละแพลตฟอร์ม:
import platform
if platform.system() != "Windows":
kwargs["preexec_fn"] = os.setsid4. Path separators
ใช้ pathlib.Path แทนการต่อ string ด้วย /
ข้อควรพิจารณาด้านความปลอดภัย (Security Considerations)
Hermes มีการเข้าถึง terminal ดังนั้นเรื่องความปลอดภัยจึงสำคัญ
การป้องกันที่มีอยู่ (Existing Protections)
| Layer | Implementation |
|---|---|
| Sudo password piping | ใช้ shlex.quote() เพื่อป้องกัน shell injection |
| Dangerous command detection | Regex patterns ใน tools/approval.py พร้อม flow การอนุมัติจากผู้ใช้ |
| Cron prompt injection | Scanner จะบล็อกรูปแบบการเขียนทับคำสั่ง (instruction-override patterns) |
| Write deny list | Protected paths ที่ถูก resolve ผ่าน os.path.realpath() เพื่อป้องกันการข้าม symlink |
| Skills guard | Security scanner สำหรับ skills ที่ติดตั้งใน hub |
| Code execution sandbox | Child process จะรันโดยที่ API keys ถูกลบออกไป |
| Container hardening | Docker: ปลดความสามารถทั้งหมด (all capabilities dropped), ไม่มี privilege escalation, มี PID limits |
การมีส่วนร่วมโค้ดที่อ่อนไหวต่อความปลอดภัย (Contributing Security-Sensitive Code)
- ใช้
shlex.quote()เสมอเมื่อแทรก user input เข้าไปใน shell commands - Resolve symlinks ด้วย
os.path.realpath()ก่อนการตรวจสอบ access control - ห้าม log secrets
- ดักจับ exceptions ทั่วไปรอบๆ tool execution
- ทดสอบบนทุกแพลตฟอร์มหากการเปลี่ยนแปลงของคุณเกี่ยวข้องกับ file paths หรือ processes
กระบวนการ Pull Request (Pull Request Process)
การตั้งชื่อ Branch (Branch Naming)
fix/description # Bug fixes
feat/description # New features
docs/description # Documentation
test/description # Tests
refactor/description # Code restructuringก่อนการส่ง (Before Submitting)
- Run tests:
pytest tests/ -v - Test manually: รัน
hermesและทดสอบ code path ที่คุณเปลี่ยนแปลง - Check cross-platform impact: พิจารณา macOS และ Linux distros ต่างๆ
- Keep PRs focused: หนึ่ง PR ต่อการเปลี่ยนแปลงเชิงตรรกะหนึ่งอย่าง
คำอธิบาย PR (PR Description)
ต้องรวม:
- อะไร ที่เปลี่ยนไป และ ทำไม
- วิธีทดสอบ
- แพลตฟอร์มใด ที่คุณทดสอบ
- อ้างอิงถึง issues ที่เกี่ยวข้อง
ข้อความ Commit (Commit Messages)
เราใช้ Conventional Commits:
<type>(<scope>): <description>| Type | Use for |
|---|---|
fix | Bug fixes |
feat | New features |
docs | Documentation |
test | Tests |
refactor | Code restructuring |
chore | Build, CI, dependency updates |
Scopes: cli, gateway, tools, skills, agent, install, whatsapp, security
ตัวอย่าง:
fix(cli): prevent crash in save_config_value when model is a string
feat(gateway): add WhatsApp multi-user session isolation
fix(security): prevent shell injection in sudo password pipingการรายงานปัญหา (Reporting Issues)
- ใช้ GitHub Issues
- ต้องรวม: OS, Python version, Hermes version (
hermes version), full error traceback - ต้องรวมขั้นตอนในการทำซ้ำ (steps to reproduce)
- ตรวจสอบ issues ที่มีอยู่ก่อนสร้าง duplicate
- สำหรับช่องโหว่ด้านความปลอดภัย โปรดรายงานแบบส่วนตัว
ชุมชน (Community)
- Discord: discord.gg/NousResearch
- GitHub Discussions: สำหรับข้อเสนอการออกแบบและการพูดคุยสถาปัตยกรรม
- Skills Hub: อัปโหลด skills เฉพาะทางและแบ่งปันกับชุมชน
License
ด้วยการมีส่วนร่วม คุณตกลงว่าการมีส่วนร่วมของคุณจะอยู่ภายใต้ MIT License
📄 developer-guide/creating-skills.md
sidebar_position: 3 title: "Creating Skills" description: "How to create skills for Hermes Agent — SKILL.md format, guidelines, and publishing"
การสร้าง Skills
Skills คือวิธีที่แนะนำในการเพิ่มความสามารถใหม่ๆ ให้กับ Hermes Agent พวกมันสร้างง่ายกว่า tools ไม่ต้องมีการเปลี่ยนแปลงโค้ดใดๆ ใน agent และสามารถแชร์กับ community ได้
ควรเป็น Skill หรือ Tool?
ให้เป็น Skill เมื่อ:
- ความสามารถนั้นสามารถแสดงเป็นชุดคำสั่ง + shell commands + tools ที่มีอยู่ได้
- มันห่อหุ้ม CLI หรือ API ภายนอกที่ agent สามารถเรียกใช้ผ่าน
terminalหรือweb_extract - ไม่จำเป็นต้องมีการผสานรวม Python หรือการจัดการ API key ที่กำหนดเองฝังอยู่ใน agent
- ตัวอย่าง: การค้นหา arXiv, git workflows, การจัดการ Docker, การประมวลผล PDF, อีเมลผ่าน CLI tools
ให้เป็น Tool เมื่อ:
- มันต้องการการผสานรวมแบบ end-to-end ด้วย API keys, auth flows, หรือการกำหนดค่าหลายส่วนประกอบ
- มันต้องการตรรกะการประมวลผลที่กำหนดเองซึ่งต้องดำเนินการอย่างแม่นยำทุกครั้ง
- มันจัดการข้อมูลไบนารี, streaming, หรือเหตุการณ์แบบ real-time
- ตัวอย่าง: browser automation, TTS, vision analysis
โครงสร้าง Directory ของ Skill
Skills ที่รวมไว้จะอยู่ใน skills/ โดยจัดระเบียบตามหมวดหมู่ Skills ทางเลือกอย่างเป็นทางการจะใช้โครงสร้างเดียวกันใน optional-skills/:
skills/
├── research/
│ └── arxiv/
│ ├── SKILL.md # Required: main instructions
│ └── scripts/ # Optional: helper scripts
│ └── search_arxiv.py
├── productivity/
│ └── ocr-and-documents/
│ ├── SKILL.md
│ ├── scripts/
│ └── references/
└── ...รูปแบบ SKILL.md
---
name: my-skill
description: Brief description (shown in skill search results)
version: 1.0.0
author: Your Name
license: MIT
platforms: [macos, linux] # Optional - restrict to specific OS platforms
# Valid: macos, linux, windows
# Omit to load on all platforms (default)
metadata:
hermes:
tags: [Category, Subcategory, Keywords]
related_skills: [other-skill-name]
requires_toolsets: [web] # Optional - only show when these toolsets are active
requires_tools: [web_search] # Optional - only show when these tools are available
fallback_for_toolsets: [browser] # Optional - hide when these toolsets are active
fallback_for_tools: [browser_navigate] # Optional - hide when these tools exist
config: # Optional - config.yaml settings the skill needs
- key: my.setting
description: "What this setting controls"
default: "sensible-default"
prompt: "Display prompt for setup"
required_environment_variables: # Optional - env vars the skill needs
- name: MY_API_KEY
prompt: "Enter your API key"
help: "Get one at https://example.com"
required_for: "API access"
---
# Skill Title
Brief intro.
## When to Use
Trigger conditions - when should the agent load this skill?
## Quick Reference
Table of common commands or API calls.
## Procedure
Step-by-step instructions the agent follows.
## Pitfalls
Known failure modes and how to handle them.
## Verification
How the agent confirms it worked.Skills เฉพาะ Platform
Skills สามารถจำกัดตัวเองให้ทำงานบนระบบปฏิบัติการที่เฉพาะเจาะจงได้โดยใช้ฟิลด์ platforms:
platforms: [macos] # macOS เท่านั้น (เช่น iMessage, Apple Reminders)
platforms: [macos, linux] # macOS และ Linux
platforms: [windows] # Windows เท่านั้นเมื่อกำหนดค่าแล้ว skill จะถูกซ่อนโดยอัตโนมัติจาก system prompt, skills_list(), และ slash commands บนแพลตฟอร์มที่ไม่รองรับ หากละเว้นหรือว่างเปล่า skill จะโหลดบนทุกแพลตฟอร์ม (รองรับย้อนหลัง)
การเปิดใช้งาน Skill แบบมีเงื่อนไข
Skills สามารถประกาศการพึ่งพา (dependencies) บน tools หรือ toolsets ที่เฉพาะเจาะจงได้ สิ่งนี้จะควบคุมว่า skill จะปรากฏใน system prompt สำหรับ session นั้นๆ หรือไม่
metadata:
hermes:
requires_toolsets: [web] # ซ่อนหาก web toolset ไม่ทำงาน
requires_tools: [web_search] # ซ่อนหาก web_search tool ไม่พร้อมใช้งาน
fallback_for_toolsets: [browser] # ซ่อนหาก browser toolset ทำงานอยู่
fallback_for_tools: [browser_navigate] # ซ่อนหาก browser_navigate มีอยู่| Field | Behavior |
|---|---|
requires_toolsets | Skill จะ ถูกซ่อน เมื่อ toolset ที่ระบุรายการใดรายการหนึ่ง ไม่ พร้อมใช้งาน |
requires_tools | Skill จะ ถูกซ่อน เมื่อ tool ที่ระบุรายการใดรายการหนึ่ง ไม่ พร้อมใช้งาน |
fallback_for_toolsets | Skill จะ ถูกซ่อน เมื่อ toolset ที่ระบุรายการใดรายการหนึ่ง ทำงาน อยู่ |
fallback_for_tools | Skill จะ ถูกซ่อน เมื่อ tool ที่ระบุรายการใดรายการหนึ่ง ทำงาน อยู่ |
กรณีการใช้งานสำหรับ fallback_for_*: สร้าง skill ที่ทำหน้าที่เป็น workaround เมื่อ tool หลักไม่พร้อมใช้งาน ตัวอย่างเช่น skill duckduckgo-search ที่มี fallback_for_tools: [web_search] จะแสดงก็ต่อเมื่อ web search tool (ซึ่งต้องใช้ API key) ไม่ได้ถูกกำหนดค่าไว้
กรณีการใช้งานสำหรับ requires_*: สร้าง skill ที่สมเหตุสมผลเมื่อมี tools บางอย่างอยู่ ตัวอย่างเช่น skill workflow สำหรับ web scraping ที่มี requires_toolsets: [web] จะไม่ทำให้ prompt รกเมื่อ web tools ถูกปิดใช้งาน
ข้อกำหนด Environment Variable
Skills สามารถประกาศ environment variables ที่ต้องการได้ เมื่อ skill ถูกโหลดผ่าน skill_view ตัวแปรที่จำเป็นจะถูกลงทะเบียนโดยอัตโนมัติสำหรับการส่งผ่าน (passthrough) เข้าสู่ sandboxed execution environments (terminal, execute_code)
required_environment_variables:
- name: TENOR_API_KEY
prompt: "Tenor API key" # แสดงเมื่อถามผู้ใช้
help: "Get your key at https://tenor.com" # ข้อความช่วยเหลือหรือ URL
required_for: "GIF search functionality" # สิ่งที่ต้องการตัวแปรนี้แต่ละรายการรองรับ:
name(required) - ชื่อ environment variableprompt(optional) - ข้อความ prompt เมื่อขอค่าจากผู้ใช้help(optional) - ข้อความช่วยเหลือหรือ URL สำหรับรับค่าrequired_for(optional) - อธิบายว่าฟีเจอร์ใดต้องการตัวแปรนี้
ผู้ใช้ยังสามารถกำหนดค่าตัวแปร passthrough ด้วยตนเองใน config.yaml:
terminal:
env_passthrough:
- MY_CUSTOM_VAR
- ANOTHER_VARดูที่ skills/apple/ สำหรับตัวอย่าง skills ที่ใช้ได้เฉพาะ macOS
การตั้งค่าที่ปลอดภัยเมื่อโหลด
ใช้ required_environment_variables เมื่อ skill ต้องการ API key หรือ token ค่าที่ขาดหายไป จะไม่ ซ่อน skill จากการค้นพบ แต่ Hermes จะแจ้งให้ผู้ใช้ทราบอย่างปลอดภัยเมื่อ skill ถูกโหลดใน local CLI แทน
required_environment_variables:
- name: TENOR_API_KEY
prompt: Tenor API key
help: Get a key from https://developers.google.com/tenor
required_for: full functionalityผู้ใช้สามารถข้ามการตั้งค่าและยังคงโหลด skill ได้ Hermes จะไม่เปิดเผยค่า secret ดิบให้ model ดู Gateway และ messaging sessions จะแสดงคำแนะนำการตั้งค่าในเครื่องแทนการรวบรวม secrets ใน-band
:::tip Sandbox Passthrough
เมื่อ skill ของคุณถูกโหลด required_environment_variables ที่ประกาศไว้และถูกตั้งค่าแล้วจะถูก ส่งผ่านโดยอัตโนมัติ ไปยัง execute_code และ terminal sandboxes รวมถึง backends ระยะไกลอย่าง Docker และ Modal สคริปต์ของ skill ของคุณสามารถเข้าถึง $TENOR_API_KEY (หรือ os.environ["TENOR_API_KEY"] ใน Python) โดยที่ผู้ใช้ไม่จำเป็นต้องกำหนดค่าอะไรเพิ่มเติม ดู Environment Variable Passthrough สำหรับรายละเอียด
:::
prerequisites.env_vars แบบเก่า ยังคงรองรับในฐานะ alias ที่รองรับย้อนหลัง
การตั้งค่า Config (config.yaml)
Skills สามารถประกาศการตั้งค่าที่ไม่ใช่ secret ซึ่งจะถูกจัดเก็บใน config.yaml ภายใต้ namespace skills.config แตกต่างจาก environment variables (ซึ่งเป็น secrets ที่จัดเก็บใน .env) การตั้งค่า config มีไว้สำหรับ paths, preferences, และค่าอื่นๆ ที่ไม่ละเอียดอ่อน
metadata:
hermes:
config:
- key: myplugin.path
description: Path to the plugin data directory
default: "~/myplugin-data"
prompt: Plugin data directory path
- key: myplugin.domain
description: Domain the plugin operates on
default: ""
prompt: Plugin domain (e.g., AI/ML research)แต่ละรายการรองรับ:
key(required) - dotpath สำหรับการตั้งค่า (เช่นmyplugin.path)description(required) - อธิบายว่าการตั้งค่านี้ควบคุมอะไรdefault(optional) - ค่าเริ่มต้นหากผู้ใช้ไม่ได้กำหนดค่าprompt(optional) - ข้อความ prompt ที่แสดงระหว่างhermes config migrate; จะ fallback ไปที่description
วิธีการทำงาน:
-
การจัดเก็บ: ค่าจะถูกเขียนลงใน
config.yamlภายใต้skills.config.<key>:skills: config: myplugin: path: ~/my-data -
การค้นพบ:
hermes config migrateจะสแกน skills ที่เปิดใช้งานทั้งหมด ค้นหาการตั้งค่าที่ยังไม่ได้กำหนดค่า และแจ้งให้ผู้ใช้ทราบ การตั้งค่ายังปรากฏในhermes config showภายใต้ "Skill Settings." -
การฉีดค่าขณะรันไทม์: เมื่อ skill โหลด ค่า config ของมันจะถูกแก้ไขและแนบไปกับข้อความ skill:
[Skill config (from ~/.hermes/config.yaml): myplugin.path = /home/user/my-data ]agent จะเห็นค่าที่กำหนดค่าแล้วโดยไม่จำเป็นต้องอ่าน
config.yamlเอง -
การตั้งค่าด้วยตนเอง: ผู้ใช้ยังสามารถตั้งค่าค่าได้โดยตรง:
hermes config set skills.config.myplugin.path ~/my-data
:::tip เมื่อไหร่ควรใช้ตัวไหน
ใช้ required_environment_variables สำหรับ API keys, tokens, และ secrets อื่นๆ (จัดเก็บใน ~/.hermes/.env, จะไม่แสดงให้ model เห็น) ใช้ config สำหรับ paths, preferences, และการตั้งค่าที่ไม่ละเอียดอ่อน (จัดเก็บใน config.yaml, แสดงใน config show)
:::
ข้อกำหนด Credential File (OAuth tokens, ฯลฯ)
Skills ที่ใช้ OAuth หรือ credentials แบบไฟล์ สามารถประกาศไฟล์ที่ต้องถูก mount เข้าไปใน remote sandboxes ได้ นี่มีไว้สำหรับ credentials ที่จัดเก็บเป็น ไฟล์ (ไม่ใช่ env vars) - โดยทั่วไปคือไฟล์ OAuth token ที่สร้างโดย setup script
required_credential_files:
- path: google_token.json
description: Google OAuth2 token (created by setup script)
- path: google_client_secret.json
description: Google OAuth2 client credentialsแต่ละรายการรองรับ:
path(required) - file path เทียบกับ~/.hermes/description(optional) - อธิบายว่าไฟล์คืออะไรและสร้างขึ้นได้อย่างไร
เมื่อโหลด Hermes จะตรวจสอบว่าไฟล์เหล่านี้มีอยู่หรือไม่ ไฟล์ที่ขาดหายไปจะกระตุ้น setup_needed ไฟล์ที่มีอยู่จะถูก:
- Mount เข้าไปใน Docker containers เป็น read-only bind mounts
- Sync เข้าไปใน Modal sandboxes (เมื่อสร้าง + ก่อนแต่ละคำสั่ง ดังนั้น OAuth กลาง session จึงใช้งานได้)
- พร้อมใช้งานบน backend local โดยไม่มีการจัดการพิเศษใดๆ
:::tip เมื่อไหร่ควรใช้ตัวไหน
ใช้ required_environment_variables สำหรับ API keys และ tokens อย่างง่าย (strings ที่จัดเก็บใน ~/.hermes/.env) ใช้ required_credential_files สำหรับไฟล์ OAuth token, client secrets, service account JSON, certificates, หรือ credentials ใดๆ ที่เป็นไฟล์บน disk
:::
ดูที่ skills/productivity/google-workspace/SKILL.md สำหรับตัวอย่างที่สมบูรณ์โดยใช้ทั้งสองอย่าง
แนวทางปฏิบัติสำหรับ Skill
ไม่มี External Dependencies
ควรใช้ stdlib Python, curl, และ tools ของ Hermes ที่มีอยู่ (web_extract, terminal, read_file) หากจำเป็นต้องมี dependency ให้บันทึกขั้นตอนการติดตั้งใน skill
Progressive Disclosure
ให้วาง workflow ที่พบบ่อยที่สุดไว้ก่อน กรณีขอบ (edge cases) และการใช้งานขั้นสูงให้ไว้ด้านล่าง สิ่งนี้ช่วยให้การใช้ token สำหรับงานทั่วไปต่ำ
รวม Helper Scripts
สำหรับการ parse XML/JSON หรือตรรกะที่ซับซ้อน ให้รวม helper scripts ใน scripts/ - อย่าคาดหวังให้ LLM เขียน parsers แบบ inline ทุกครั้ง
การอ้างอิง scripts ที่รวมไว้จาก SKILL.md
เมื่อ skill ถูกโหลด ข้อความ activation จะเปิดเผย directory ของ skill แบบ absolute เป็น [Skill directory: /abs/path] และยังแทนที่ template tokens สองตัวได้ทุกที่ในเนื้อหา SKILL.md:
| Token | Replaced with |
|---|---|
${HERMES_SKILL_DIR} | Absolute path ไปยัง directory ของ skill |
${HERMES_SESSION_ID} | active session id (คงไว้หากไม่มี session) |
ดังนั้น SKILL.md สามารถบอก agent ให้รัน bundled script โดยตรงด้วย:
To analyse the input, run:
node ${HERMES_SKILL_DIR}/scripts/analyse.js <input>agent จะเห็น absolute path ที่ถูกแทนที่และเรียกใช้ tool terminal ด้วยคำสั่งที่พร้อมรัน - ไม่ต้องคำนวณ path, ไม่ต้อง round-trip skill_view เพิ่มเติม สามารถปิดการแทนที่ทั่วโลกได้ด้วย skills.template_vars: false ใน config.yaml
Inline shell snippets (opt-in)
Skills ยังสามารถฝัง inline shell snippets ที่เขียนเป็น !`cmd` ในเนื้อหา SKILL.md ได้ เมื่อเปิดใช้งาน stdout ของ snippet แต่ละตัวจะถูกรวมเข้ากับข้อความก่อนที่ agent จะอ่าน ทำให้ skills สามารถฉีด dynamic context ได้:
Current date: !`date -u +%Y-%m-%d`
Git branch: !`git -C ${HERMES_SKILL_DIR} rev-parse --abbrev-ref HEAD`สิ่งนี้ ปิดอยู่โดยค่าเริ่มต้น - snippet ใดๆ ใน SKILL.md จะรันบน host โดยไม่มีการอนุมัติ ดังนั้นให้เปิดใช้งานเฉพาะสำหรับแหล่งที่มาของ skill ที่คุณเชื่อถือเท่านั้น:
# config.yaml
skills:
inline_shell: true
inline_shell_timeout: 10 # seconds per snippetSnippets รันด้วย skill directory เป็น working directory และ output ถูกจำกัดที่ 4000 characters ความล้มเหลว (timeouts, non-zero exits) จะแสดงเป็น marker สั้นๆ [inline-shell error: ...] แทนที่จะทำให้ skill ทั้งหมดล้มเหลว
การทดสอบ
รัน skill และตรวจสอบว่า agent ทำตามคำแนะนำอย่างถูกต้อง:
hermes chat --toolsets skills -q "Use the X skill to do Y"Skill ควรอยู่ตรงไหน?
Skills ที่รวมไว้ (ใน skills/) มาพร้อมกับการติดตั้ง Hermes ทุกครั้ง พวกมันควรมี ประโยชน์ในวงกว้างสำหรับผู้ใช้ส่วนใหญ่:
- การจัดการเอกสาร, web research, common dev workflows, system administration
- ถูกใช้งานเป็นประจำโดยผู้คนหลากหลายกลุ่ม
หาก skill ของคุณเป็น official และมีประโยชน์แต่ไม่ได้จำเป็นสำหรับทุกคน (เช่น การผสานรวมบริการแบบเสียเงิน, dependency ที่มีน้ำหนักมาก) ให้ใส่ไว้ใน optional-skills/ - มันจะมาพร้อมกับ repo, สามารถค้นพบได้ผ่าน hermes skills browse (ติดป้าย "official"), และติดตั้งด้วยความเชื่อถือในตัว
หาก skill ของคุณมีความเฉพาะทาง, มีการสนับสนุนจาก community, หรือเป็น niche, จะเหมาะกับ Skills Hub มากกว่า - อัปโหลดไปยัง registry และแชร์ผ่าน hermes skills install
การเผยแพร่ Skills
ไปยัง Skills Hub
hermes skills publish skills/my-skill --to github --repo owner/repoไปยัง Custom Repository
เพิ่ม repo ของคุณเป็น tap:
hermes skills tap add owner/repoผู้ใช้สามารถค้นหาและติดตั้งจาก repository ของคุณได้
Security Scanning
skills ทั้งหมดที่ติดตั้งผ่าน hub จะผ่าน security scanner ที่ตรวจสอบ:
- Data exfiltration patterns
- Prompt injection attempts
- Destructive commands
- Shell injection
ระดับความเชื่อถือ:
builtin- มาพร้อมกับ Hermes (เชื่อถือได้เสมอ)official- จากoptional-skills/ใน repo (builtin trust, ไม่มีคำเตือน third-party)trusted- จาก openai/skills, anthropics/skillscommunity- ผลลัพธ์ที่ไม่เป็นอันตรายสามารถถูก override ด้วย--force; ผลลัพธ์dangerousยังคงถูกบล็อก
ตอนนี้ Hermes สามารถใช้ third-party skills จาก multiple external discovery models:
- direct GitHub identifiers (เช่น
openai/skills/k8s) skills.shidentifiers (เช่นskills-sh/vercel-labs/json-render/json-render-react)- well-known endpoints ที่ให้บริการจาก
/.well-known/skills/index.json
หากคุณต้องการให้ skills ของคุณสามารถค้นพบได้โดยไม่จำเป็นต้องมี installer เฉพาะ GitHub ให้พิจารณาให้บริการจาก well-known endpoint นอกเหนือจากการเผยแพร่ใน repo หรือ marketplace
📄 developer-guide/cron-internals.md
sidebar_position: 11 title: "Cron Internals" description: "How Hermes stores, schedules, edits, pauses, skill-loads, and delivers cron jobs"
Cron Internals
ระบบ cron subsystem ให้การทำงานตามตารางเวลา (scheduled task execution) ตั้งแต่การหน่วงเวลาแบบครั้งเดียว (one-shot delays) ไปจนถึงงานแบบ cron-expression ที่มีการทำซ้ำ (recurring) พร้อมการฉีด skill และการส่งมอบข้ามแพลตฟอร์ม
Key Files
| File | Purpose |
|---|---|
cron/jobs.py | Job model, storage, atomic read/write to jobs.json |
cron/scheduler.py | Scheduler loop - due-job detection, execution, repeat tracking |
tools/cronjob_tools.py | Model-facing cronjob tool registration and handler |
gateway/run.py | Gateway integration - cron ticking in the long-running loop |
hermes_cli/cron.py | CLI hermes cron subcommands |
Scheduling Model
รองรับรูปแบบการกำหนดเวลา 4 รูปแบบ:
| Format | Example | Behavior |
|---|---|---|
| Relative delay | 30m, 2h, 1d | One-shot, fires after the specified duration |
| Interval | every 2h, every 30m | Recurring, fires at regular intervals |
| Cron expression | 0 9 * * * | Standard 5-field cron syntax (minute, hour, day, month, weekday) |
| ISO timestamp | 2025-01-15T09:00:00 | One-shot, fires at the exact time |
ส่วนที่เปิดให้ใช้งาน (surface) สำหรับ model คือ cronjob tool ตัวเดียว ที่มี operations แบบ action: create, list, update, pause, resume, run, remove
Job Storage
Jobs ถูกจัดเก็บใน ~/.hermes/cron/jobs.json ด้วย semantics การเขียนแบบ atomic (เขียนไปยัง temp file แล้วจึงเปลี่ยนชื่อ) แต่ละ record ของ job ประกอบด้วย:
{
"id": "a1b2c3d4e5f6",
"name": "Daily briefing",
"prompt": "Summarize today's AI news and funding rounds",
"schedule": {
"kind": "cron",
"expr": "0 9 * * *",
"display": "0 9 * * *"
},
"skills": ["ai-funding-daily-report"],
"deliver": "telegram:-1001234567890",
"repeat": {
"times": null,
"completed": 42
},
"state": "scheduled",
"enabled": true,
"next_run_at": "2025-01-16T09:00:00Z",
"last_run_at": "2025-01-15T09:00:00Z",
"last_status": "ok",
"created_at": "2025-01-01T00:00:00Z",
"model": null,
"provider": null,
"script": null
}Job Lifecycle States
| State | Meaning |
|---|---|
scheduled | Active, will fire at next scheduled time |
paused | Suspended - won't fire until resumed |
completed | Repeat count exhausted or one-shot that has fired |
running | Currently executing (transient state) |
Backward Compatibility
Jobs เก่าอาจมี field skill เพียงตัวเดียวแทนที่จะเป็น array skills Scheduler จะทำการ normalize สิ่งนี้ในขณะโหลด - single skill จะถูก promote เป็น skills: [skill]
Scheduler Runtime
Tick Cycle
Scheduler ทำงานเป็นรอบ tick ตามช่วงเวลา (ค่าเริ่มต้น: ทุก 60 วินาที):
tick()
1. Acquire scheduler lock (prevents overlapping ticks)
2. Load all jobs from jobs.json
3. Filter to due jobs (next_run <= now AND state == "scheduled")
4. For each due job:
a. Set state to "running"
b. Create fresh AIAgent session (no conversation history)
c. Load attached skills in order (injected as user messages)
d. Run the job prompt through the agent
e. Deliver the response to the configured target
f. Update run_count, compute next_run
g. If repeat count exhausted → state = "completed"
h. Otherwise → state = "scheduled"
5. Write updated jobs back to jobs.json
6. Release scheduler lockGateway Integration
ในโหมด gateway, scheduler tick จะถูกรวมเข้ากับ main event loop ของ gateway Gateway จะเรียกใช้ scheduler.tick() ในรอบการบำรุงรักษาตามช่วงเวลา ซึ่งทำงานควบคู่ไปกับการจัดการข้อความ
ในโหมด CLI, cron jobs จะทำงานก็ต่อเมื่อมีการรันคำสั่ง hermes cron หรือระหว่าง active CLI sessions เท่านั้น
Fresh Session Isolation
แต่ละ cron job จะทำงานใน agent session ที่สดใหม่โดยสมบูรณ์:
- ไม่มี conversation history จากการรันครั้งก่อนหน้า
- ไม่มี memory ของการ execute cron ครั้งก่อนหน้า (เว้นแต่จะถูก persist ไปยัง memory/files)
- Prompt ต้องเป็น self-contained - cron jobs ไม่สามารถถามคำถามเพื่อขอความชัดเจนได้
cronjobtoolset ถูกปิดใช้งาน (recursion guard)
Skill-Backed Jobs
cron job สามารถแนบ skill หนึ่งตัวหรือมากกว่าผ่าน field skills เมื่อถึงเวลา execute:
- Skills จะถูกโหลดตามลำดับที่กำหนด
- เนื้อหา SKILL.md ของแต่ละ skill จะถูกฉีดเป็น context
- Prompt ของ job จะถูกต่อท้ายเป็นคำสั่งงาน
- Agent จะประมวลผล combined skill context + prompt
สิ่งนี้ช่วยให้สามารถสร้าง workflow ที่นำกลับมาใช้ใหม่ได้และผ่านการทดสอบ โดยไม่ต้องวางคำสั่งทั้งหมดลงใน cron prompts ตัวอย่างเช่น:
Create a daily funding report → attach "ai-funding-daily-report" skillScript-Backed Jobs
Jobs ยังสามารถแนบ Python script ผ่าน field script ได้ Script จะทำงาน ก่อน แต่ละ agent turn และ stdout ของ script จะถูกฉีดเข้าไปใน prompt เป็น context สิ่งนี้ช่วยให้สามารถทำ data collection และ change detection patterns:
# ~/.hermes/scripts/check_competitors.py
import requests, json
# Fetch competitor release notes, diff against last run
# Print summary to stdout - agent analyzes and reportsScript timeout จะตั้งค่าเริ่มต้นที่ 120 วินาที ฟังก์ชัน _get_script_timeout() จะหาขีดจำกัดผ่าน chain สามชั้น:
- Module-level override -
_SCRIPT_TIMEOUT(สำหรับ tests/monkeypatching) ใช้เฉพาะเมื่อค่าแตกต่างจากค่าเริ่มต้นเท่านั้น - Environment variable -
HERMES_CRON_SCRIPT_TIMEOUT - Config -
cron.script_timeout_secondsในconfig.yaml(อ่านผ่านload_config()) - Default - 120 seconds
Provider Recovery
run_job() จะส่ง fallback providers และ credential pool ที่กำหนดค่าโดยผู้ใช้เข้าสู่ instance AIAgent:
- Fallback providers - อ่านจาก
fallback_providers(list) หรือfallback_model(legacy dict) จากconfig.yamlโดยตรงกับรูปแบบ_load_fallback_model()ของ gateway ส่งเป็นfallback_model=ไปยังAIAgent.__init__ซึ่งจะ normalize ทั้งสองรูปแบบให้เป็น fallback chain - Credential pool - โหลดผ่าน
load_pool(provider)จากagent.credential_poolโดยใช้ชื่อ provider runtime ที่ resolve แล้ว จะถูกส่งก็ต่อเมื่อ pool มี credentials (pool.has_credentials()) ช่วยให้สามารถหมุนเวียน key ของ provider เดียวกันได้เมื่อเกิดข้อผิดพลาด 429/rate-limit
สิ่งนี้สะท้อนพฤติกรรมของ gateway - หากไม่มีส่วนนี้ cron agents จะล้มเหลวเมื่อเกิด rate limits โดยไม่ได้พยายามกู้คืน
Delivery Model
ผลลัพธ์ของ cron job สามารถส่งไปยังแพลตฟอร์มที่รองรับได้ทุกประเภท:
| Target | Syntax | Example |
|---|---|---|
| Origin chat | origin | Deliver to the chat where the job was created |
| Local file | local | Save to ~/.hermes/cron/output/ |
| Telegram | telegram หรือ telegram:<chat_id> | telegram:-1001234567890 |
| Discord | discord หรือ discord:#channel | discord:#engineering |
| Slack | slack | Deliver to Slack home channel |
whatsapp | Deliver to WhatsApp home | |
| Signal | signal | Deliver to Signal |
| Matrix | matrix | Deliver to Matrix home room |
| Mattermost | mattermost | Deliver to Mattermost home |
email | Deliver via email | |
| SMS | sms | Deliver via SMS |
| Home Assistant | homeassistant | Deliver to HA conversation |
| DingTalk | dingtalk | Deliver to DingTalk |
| Feishu | feishu | Deliver to Feishu |
| WeCom | wecom | Deliver to WeCom |
| Weixin | weixin | Deliver to Weixin (WeChat) |
| BlueBubbles | bluebubbles | Deliver to iMessage via BlueBubbles |
| QQ Bot | qqbot | Deliver to QQ (Tencent) via Official API v2 |
สำหรับหัวข้อของ Telegram ให้ใช้รูปแบบ telegram:<chat_id>:<thread_id> (เช่น telegram:-1001234567890:17585)
Response Wrapping
โดยค่าเริ่มต้น (cron.wrap_response: true), การส่งมอบของ cron จะถูกห่อด้วย:
- Header ที่ระบุชื่อ cron job และ task
- Footer ที่แจ้งว่า agent ไม่สามารถเห็นข้อความที่ส่งมอบใน conversation ได้
Prefix [SILENT] ใน cron response จะระงับการส่งมอบโดยสมบูรณ์ - มีประโยชน์สำหรับ jobs ที่ต้องการเขียนไปยังไฟล์เท่านั้นหรือทำ side effects
Session Isolation
Cron deliveries จะไม่ถูกสะท้อน (mirrored) เข้าไปใน gateway session conversation history พวกมันมีอยู่เฉพาะใน session ของ cron job เองเท่านั้น สิ่งนี้ป้องกันการละเมิด message alternation ใน conversation ของ target chat
Recursion Guard
Session ที่รัน cron จะปิดใช้งาน cronjob toolset สิ่งนี้ป้องกัน:
- การที่ scheduled job สร้าง cron jobs ใหม่
- การทำ recursive scheduling ที่อาจทำให้ token usage ระเบิด
- การแก้ไข job schedule โดยไม่ได้ตั้งใจจากภายใน job
Locking
Scheduler ใช้ file-based locking เพื่อป้องกันไม่ให้เกิดการทำงานซ้ำของ batch due-job จากการที่ multiple maintenance cycles ทับซ้อนกัน ซึ่งสำคัญในโหมด gateway ที่รอบการบำรุงรักษาหลายรอบอาจทับซ้อนกันได้หาก tick ก่อนหน้าใช้เวลานานกว่าช่วงเวลาของ tick
CLI Interface
hermes cron CLI ให้การจัดการ job โดยตรง:
hermes cron list # Show all jobs
hermes cron create # Interactive job creation (alias: add)
hermes cron edit <job_id> # Edit job configuration
hermes cron pause <job_id> # Pause a running job
hermes cron resume <job_id> # Resume a paused job
hermes cron run <job_id> # Trigger immediate execution
hermes cron remove <job_id> # Delete a jobRelated Docs
extent analysis
TL;DR
To resolve the issue, review the configuration settings for the ContextCompressor and ensure that the threshold and target ratio are properly set, and consider adjusting the protect_last_n parameter to preserve more recent messages.
Guidance
- Check configuration settings: Verify that the
compressionsettings inconfig.yamlare correctly configured, paying attention tothreshold,target_ratio, andprotect_last_n. - Adjust threshold and target ratio: If necessary, adjust the
thresholdandtarget_ratioto balance between context preservation and compression. - Review protect_last_n: Consider increasing
protect_last_nto preserve more recent messages and prevent important context from being lost during compression. - Test and iterate: After making changes, test the compression behavior and adjust settings as needed to achieve the desired balance between context preservation and compression efficiency.
Example
No specific code example is provided as the issue seems to be related to configuration rather than code. However, ensuring that the config.yaml contains appropriate settings for compression, such as:
compression:
enabled: true
threshold: 0.50
target_ratio: 0.20
protect_last_n: 20can help in managing context compression effectively.
Notes
- The effectiveness of compression and the preservation of context depend heavily on the specific use case and the nature of the conversations.
- Regularly reviewing and adjusting compression settings may be necessary as the usage patterns and requirements evolve.
Recommendation
Apply adjustments to the compression settings in config.yaml to better suit the specific needs of the application, focusing on finding an optimal balance between preserving context and efficiently managing conversation history.
Vote matrix · Quick signals
Still need to ship something?
×6Another batch ranked right after the header list — different links, same matching logic.
TRENDING
- Feature Request: Configurable per-minute rate limiting (RPM) for models to prevent 429 errors
- Android: Hermes App + Termux install share ~/.hermes and cause silent permission loops
- hermes update emits unicode-animations ANSI demo in non-interactive logs
- hermes update downgrades aiohttp from 3.13.4 to 3.13.3
- npm install warns about deprecated @babel/plugin-proposal-private-methods
- DingTalk inbound media URLs are skipped as unreadable native image paths
- fix(dashboard): ChatPage clears header action buttons on ALL pages, not just Sessions
- [Bug]: check_web_api_key() hardcodes built-in backends — third-party web search plugins silently disabled
- Hermes Web UI 修复经验:GatewayManager 补丁、进程 D 状态、数据库升级问题
- Telegram gateway can silently drop turn after /stop with response=0 chars while internal work continues
- Bug Report: v0.14.0 上下文污染 — 历史回复碎片回注到新请求
- Bug: hermes skills search table truncates Identifier column — install fails with copied value
- [skills-index-watchdog] Skills index is stale or degraded (degraded)
- Discord approval embed not rendering on web/mobile — embed data present in API but invisible
- Idea: Discord voice-channel participation / opt-in auto-join mode
- [Feature]: Claude Code--ultrawork
- build-arm64 job deterministically fails on cold cache (Azure SAS token expires mid-build)
- [Enhancement] computer_use: action=type should fall back to key events for terminal emulators (Ghostty/Terminal.app/iTerm2)
- Feature Request: Session Recovery on Temporary Provider Outage
- [Bug]: Hermes dashboard not working on NixOS (container)
- [Feature]: Add option to ignore @all/@everyone mentions in Feishu group chats
- QQ Bot WebSocket 频繁断开:长时间工具执行阻塞 asyncio 事件循环导致心跳超时
- patch tool: new_string escape sequences (\t) get written literally
- Feature Request: i18n / 多语言支持(国际化)
- Bug: web_crawl schema lets models auto-guess "instructions" instead of asking the user via clarify
- feat: `!command` prefix for direct shell execution (like Claude Code)
- Expose currently-running cron jobs via /api/jobs (or new endpoint)
- [Bug]: Kanban parent-child handoff: scratch workspace GC destroys artifacts before child can read them
- [Bug, Windows] hermes gateway restart loses session context — planned_stop_marker not written before SIGTERM
- [Bug]: Codex→DeepSeek fallback sends assistant turns without reasoning_content → HTTP 400 (require-side cross-provider failover)
- [Bug]: Update got stuck half way, reboot it, then ModuleNotFoundError: No module named 'hermes_cli'
- Kanban dispatcher corrupt-board handling and multi-profile gateway ownership ambiguity
- Gateway can resend a short fallback message when the real final Telegram response was already delivered
- [BUG] Bedrock: Fix 'Invalid API Key format' for presigned URL tokens
- Secret redaction corrupts code syntax in tool output (write_file, execute_code, terminal)
- Unable to connect Ollama Cloud with Pro Subscription to Hermes
- feat: fuzzy substring matching for /skill autocomplete
- PRD: Autonomous market-impact prediction briefing system
- Kanban dashboard should support task/card deep links
- [Feature] Native Feishu CardKit Streaming: consolidate best-in-class implementations
- [Feature]: Inject mental model into context when using Hindsight
- Interactive CLI hides tool output despite display.tool_progress=all, and hermes chat -v does not restore it
- fix(api_server): _handle_responses drops text.format JSON schema — structured output constraints silently ignored
- state.db FTS corruption goes undetected — no integrity check, no repair path
- bug: fallback routing can select text-only models for image requests and hide the primary failure
- feat(kanban): persist worker session_id per run and pass --resume on respawn after unblock
- feat(kanban): support GitHub/OMO lifecycle bridge for Xiyou-style automation
- Expose update-safe TUI/composer hooks for voice transcript and composer events
- Hide or configure voice transcript status rows in editable dictation mode
- [Feature]: Per-Tool / Per-Toolset Approval Policies
- Context compression creates orphan sessions missing from state.db
- messaging platform
- feat: Add read-only / silent monitoring mode for WhatsApp adapter
- double-.hermes path mismatch, the HOME env var leak, and the fallback-notification UX problem
- Bug: Plattform-Bundle name `hermes-yuanbao` in `agent.disabled_toolsets` silently kills ALL tools in gateway path (Telegram + cron), CLI unaffected
- CLI /yolo (in-chat) does not bypass dangerous command approvals — env var freeze + missing enable_session_yolo call
- OpenAI Codex provider crashes with "'NoneType' object is not iterable" (HTTP None)
- DEEPSEEK_API_KEY blocked by env blocklist in gateway process — cron jobs fail with deepseek provider
- fix(feishu): Card action callback routing issues - invalid message_id and unrecognized /card command
- Discord plugin: profiles without explicit `discord:` block silently get `require_mention=true` + `auto_thread=true` (regression in cc8e5ec2a)
- [Bug]: DISCORD_ALLOWED_ROLES ignored by gateway _is_user_authorized — role-authorized users get 'Unauthorized user' rejection
- [Bug]: /new, /clear, and /reset commands freeze the terminal session
- openai-codex subscription backend returns HTTP 200 with response.output=None, causing Slack/cron failures
- RFC: Centralized Model/Provider Registry
- bug: openai-codex provider — TypeError: 'NoneType' object is not iterable on every request (gpt-5.5)
- [Feature]: Source-aware instruction gate — architectural mitigation for indirect prompt injection
- Named custom provider stale_timeout_seconds ignored because runtime provider is normalized to `custom`
- guard test (ignore)
- [Feature]: per-platform LLM request_overrides (extra_body / reasoning_effort / service_tier)
- One-shot smoke: add Flue-backed orchestration fixture
- Gateway should not treat stale Codex app-server progress as final response after post-tool silence
- `docker_run_as_host_user: true` breaks bundled skills: Hermes home is mounted into `/root/.hermes` but the container runs as a non-root user (`HOME=/home/pn`)
- [Bug]: gateway api_server streaming bypasses server-side tool-call loop when chat_template_kwargs.enable_thinking=false (model emits tool name as plain text)
- [Feature]: Pre-install python-telegram-bot in Umbrel Hermes Docker image
- YouTube Shorts filter not working in youtube-content skill
- v0.15.0 PyPI release breaks ALL platforms — plugin.yaml manifests missing from package
- RFC: On-demand tool/skill/MCP discovery — decouple schema registration from process lifecycle
- Pixshelf: local-first stock photo workflow command center
- [Bug]: baoyu infographic skill should not silently bypass image_generate
- Pixshelf v1.5: manual submission tracking for stock agencies
- `hermes config set` silently accepts unknown keys, writing them where the runtime never reads
- Honcho memory prefetch hang on fresh CLI subprocess in v0.15.0 (regression from #27190)
- [Bug] v0.15.0 Docker image: stage2-hook.sh, main-wrapper.sh missing; container_boot module removed
- Feature: Reduce cache-read token overhead for DeepSeek providers — configurable cache_ttl, skills snapshot trimming, memory compaction
- Windows: three bugs from daily use (plugin discovery, gateway exit code, Unicode decode
- holographic memory: HRR silently degrades to FTS5 when numpy is missing
- Make max_tokens configurable for aux vision calls
- Conversation compression desynchronizes session ID between agent context and gateway routing, causing silent message loss
- [Bug]: v0.15.0 Docker image:The TUI cannot be used in the dashboard.
- cron: skip_memory=True blocks fact_store/memory tools from all cron jobs
- TUI: Node.js OOM crash when agent uses browser tools repeatedly
- feat: model_profiles — per-model toolset and memory config
- Automatic background skill patching disrupts active sessions (severe impact on local models)
- ensure_hermes_home() creates root-owned dirs in profile subdirectories when kanban workers are dispatched
- Feature: opt-in webhook bypass for DISCORD_ALLOW_BOTS — allow operator-initiated probes without weakening bot-loop guard
- v0.15.0: Codex requests fail HTTP 400 when participant display_name contains non-ASCII (emoji breaks input[].name pattern)
- Architecture: State Persistence Precedence (Memory vs Skills vs Hooks)
- [Bug]: cronjob tool: create action always fails with "schedule is required for create" even when parameters are provided
- codex-oauth: 'NoneType' object is not iterable in _run_codex_stream (gpt-5.5) — every turn fails non-retryably
- Docs/Config: Plugin local scope enablement ambiguity
- [Bug]: CLI freezes after using /new command (WSL)
- Profile Codex auth can ignore global credential pool when local state is stale
- [workflow-engine] CRITICAL: variable substitution crashes on regex metachars in user input
- [workflow-engine] HIGH: loop and bash nodes leak subprocesses on timeout
- [workflow-engine] HIGH: README documents config env vars the engine never reads
- [workflow-engine] MEDIUM: workflow_run rate limit bypassable via concurrent calls (TOCTOU)
- [workflow-engine] chore: manifest gaps, side-effectful register(), dead code, unauth kanban dispatch
- [mcp_lazy] HIGH: synthetic mcp_server_<name> stub collides with a real MCP server named 'server'
- [mcp_lazy] HIGH: promote_server eager flag documented but never persisted
- [mcp_lazy] MEDIUM: _prev_mode dict leaks and goes stale; not cleared on session evict
- [mcp_lazy] MEDIUM: get_pool has unlocked check-then-set race on pool creation
- [mcp_lazy] MEDIUM: pre_tool_call gives no guidance for unpromoted server-stub calls
- [mcp_lazy] chore: undeclared pre_tool_call hook, nonexistent 'mcp_load_tools' name in docs, missing tests
- [a2a_fleet] CRITICAL: server never auto-starts — register() runs outside an event loop
- [a2a_fleet] CRITICAL: auth_required defaults to false on a cross-machine surface
- [a2a_fleet] HIGH: remove invented disable() hook — loader never calls it, port leaks on reload
- [a2a_fleet] HIGH: plugin.yaml missing kind / provides_tools / requires_env (token env undeclared)
- [a2a_fleet] MEDIUM: tighten wide-open CORS, anonymous /health peer leak, and peer-URL SSRF
- [a2a_fleet] MEDIUM: relocate tests to tests/plugins/ and cover sync-register + auth-default paths
- xai-oauth auxiliary client incorrectly uses Responses API (CodexAuxiliaryClient), causing 403 on compression/vision/web_extract
- [Bug]: Direct Copilot gpt-5.5 large resumes are killed by 12s Codex TTFB watchdog
- [Bug]: `hermes uninstall` does not work on Windows
- TUI: Thinking block leaks raw JSON and Σ character
- Hostinger VPS: migration Hermes Agent → Hermes WebUI impossible (tini + UID mismatch + sessions)
- /goal judge over-continues exploratory goals unless the assistant explicitly says the goal is complete
- /goal auto-continuation can be amplified by preflight compression/session split and resurrect stale task state
- Dashboard infinite reload loop in loopback mode — GET /api/auth/me returns 401 on every page load
- [Bug]: Provider/LLM switch leaves stale encrypted_content causing 400 errors on Telegram sessions
- [Bug]: Infinite reload loop / React state loop on Sessions tab (Firefox + Chrome) — repeated 401 on /api/auth/me (v0.15.0)
- show_reasoning should work independently of streaming in CLI mode
- Feature Request: Strip reasoning/<think> blocks from TTS preprocessing
- mcp add / mcp test raise NameError when mcp package not installed
- v0.14.0 dashboard breaks behind reverse proxies — two regressions
- Skills hub creates empty category directories when no skills installed
- [Bug]: Custom endpoint: ChatCompletions returns content, but Hermes treats response as empty (v0.14.0)
- fix: atomic_replace() fails with EXDEV when HERMES_HOME is a cross-filesystem symlink
- fix(gateway): Feishu session cancellation orphans session guard, permanently blocking messages
- Custom endpoint pricing can overestimate Crof qwen3.5-9b cost by 1,000,000x
- MCP OAuth callback: module-level port global causes port collisions and structural weaknesses vs upstream
- Bug: send_message tool bypasses validate_media_delivery_path security check
- Proposal: Add Mnemosyne to official memory provider documentation
- feat(swarm): support custom verifier/synthesizer body + skills
- Template conversion failed
- Error occurred in the operation of the agent node in the workflow.
- PubSub client overrides Sentinel client when REDIS_USE_SENTINEL is enabled
- Frontend description of the Retrieval node output does not match the actual output
- JSON type input var raise Intenal server error
- cannot extract elements from a scalar
- 负载均衡 为模型配置多组凭据,并自动调用,此功能无法选择
- add models is error
- panic: could not create filter
- Persist partially generated messages when /chat-messages/:task_id/stop is called
- MCP server connection fails with 403 — request never leaves Dify (SSRF proxy suspected)
- Support durable async execution backends for long-running workflow steps
- [Xiaomi MiMo] Credentials validation fails with 400 "Not supported model mimo-v2-flash" when using Token Plan endpoint (v0.0.7)
- After clicking preview on a parent-child segmented knowledge base, it shows 0 chunks
- Retrieval score differs between UI upload (.docx) and API upload (.txt) despite identical chunk content and embedding model
- gemini cli crash again
- Xbox gift card code damage
- Damage caused by the gemini cli crash
- ioctl(2) failed, EBADF (Bad File Descriptor)
- Feat: Support Bun as an alternative runtime/package manager for updates and extensions
- fatal error again!!!!
- ioctl error
- Critical Crash: ioctl(2) failed, EBADF in ShellExecutionService.resizePty
- ioctl(2) failed, EBADF
- v0.44.0 Regression: Critical crash with ioctl(2) failed, EBADF during PTY resize
- Crash on startup: ioctl(2) failed, EBADF in UnixTerminal.resize
- Crash: `ioctl(2) failed, EBADF` in `node-pty` during PTY resize on macOS
- Gemini CLI crashes with `ioctl(2) failed, EBADF` in `node-pty` during `resizePty`
- Remote Role
- ERROR ioctl(2) failed, EBADF /home/mich
- RangeError: Maximum call stack size exceeded
- EBADF Error during folder creationg broke session and terminal glitches
- MAIP / Gargoub Project - Mediterania - North Coast
- Gemini cli crash again in this morning
- ERROR ioctl(2) failed, EBADF
- Verified node install fails — Checksum verification failed (Cloud)
- The extended debugging key did not arrive during registration.
- CollaborationPane unmounts collaboration store on single-user instances, causing permanent "No network connection" state
- Workflow cannot be saved when the name contains "->" (Potentially malicious string)
- automation does not work and does not show an error
- Raj Ai Automation
- Default Data Loader: DOMMatrix is not defined error
- Feature: Per-node execution timestamp overlay on canvas during workflow run
- AI Agent + Vertex `gemini-3.5-flash`: 400 "missing thought_signature" on sequential multi-turn tool calls (post-#24982)
- PDF Loader in Pinecone Vector Store fails due to pdf-parse version conflict (v2 not supported)
- emailReadImap: add UID deduplication, batch size cap, and numeric uid enforcement
- Manual node execution fails with "Could not find a node" when autosave is disabled (N8N_WORKFLOWS_AUTOSAVE_DISABLED)
- Schedule Trigger stopped firing — workflow Published & active, manual executions succeed, no automated fires for 2+ hours
- [MCP SDK] create_workflow_from_code intermittently returns HTTP 500, often as a false negative (workflow persists anyway, causing duplicates on retry)
- Credential-load wedge: workflows using googleApi/jwtAuth credentials silently fail to execute after key rotation
- Google Sheets Trigger every minute is not working manual Execute is working sent email
- [BUG] Plugin marketplace MCP connector remains stuck "still connecting" when mcp-remote requires OAuth
- [redacted at user request]
- Opus 4.7 behavioral regression: loaded instruction-following discipline degraded in recent Claude Code/Cowork updates
- [BUG] Tailscale via Homebrew CLI + Mac App Store GUI, both Macs on macOS, Cowork blocked by VPN detector despite Tailscale being a mesh VPN with no traffic interception
- stopShellPty on tab switch kills active sessions (exit 143) — regression in May 27 build
- [BUG] Long URLs are broken into multiple lines and become unclickable in terminal output
- [BUG] claude rm/stop/reap SIGKILLs background session tree without SIGTERM grace, orphaning git index.lock and similar
- [BUG] Default git workflow in the system prompt was pushed without context or consent
- [MODEL] Inconsistent output quality / Ignoring instructions (overfitting and inappropriate repetition of Korean vocabulary)
- You've hit your weekly limit · resets May 31 at 5pm (Asia/Shanghai)
- Paid yearly subscription silently downgraded to Free with no user action
- [Regression v2.1.153] Plugin bash hooks fail with "echo: write error: Permission denied" on Windows (claude-mem, shell: "bash")
- [BUG] Connector toggles in conversation are not clickable — must click text label instead
- [remote-control] Input from mobile app/browser not reaching host session — output works fine
- Model fails to read/reference CLAUDE.md contents despite being loaded in context
- [BUG] Claude Desktop reinstall destroys Code chat history (transcripts + Recents) while regular Chat history, project files, and memory all survive
- Bypass mode clamps to Accept Edits even with the toggle ON (Claude Code Desktop 1.9255.2 / CC 2.1.149)
- [BUG] TUI input freezes randomly mid-typing — entire prompt becomes unresponsive for minutes
- [BUG] Cowork downloads Linux ELF binary instead of macOS binary on macOS Sonoma 14.8.7 — exit code 132 (SIGILL) on every session
- [Feature Request] Persistent project memory — sessions forget everything on close, forcing users to keep many sessions open
- [Bug] Thread context stale after sleep/resume, returns outdated date and calendar data
- [FEATURE] Add context window usage indicator and warning before auto-compaction
- [BUG] Dictation error: Invalid character in header content ["x-config-keyterms"] on Windows
- [Bug] Anthropic API Error: Server rate limiting despite normal usage
- Does delegating work to `claude -p` subprocesses reduce context accumulation in the parent session?
- [BUG] Claude Code hangs on M1 Mac when terminal says "opening browser to sign in" and browser opens
- [BUG] Claude_Preview MCP preview_start spawns dev server with main-repo cwd instead of session's worktree cwd
- [Bug] Anthropic API Error: Server rate limiting during request execution
- [Bug] Anthropic API Error: Server rate limiting on concurrent requests
- [Bug] Ultraplan ready notification fires before cloud agent completes execution
- [BUG] API 500 ERROR ALL THROUGHOUT THE DAY
- [BUG] Cowork: Live Artifacts folder path changed in 1.9255.2, no automatic migration from Documents\Claude\Artifacts
- [Bug] Auto-compact never triggers despite statusline reporting "100% context used" (v2.1.153, Max sub, 200K mode)
- [BUG] [Desktop / macOS] 'Open in → New Window' detached session: font renders smaller than main, no per-window controls, Cmd+/Cmd- keystrokes routed to main window instead
- Feature request: option to switch between classic and new minimal UI
- [Feature Request] Show timestamps for each message
- [BUG] Terminal corruption when permission prompt appears while navigating Agent Teams agent selection menu
- [FEATURE] Allow users to customize the background color of the Claude desktop app beyond the current light/dark theme presets.
- [BUG] Statusline not displaying on Windows [fixed]
- Background agent UI Stop button is a no-op for stuck agents — process keeps consuming tokens
- Background agents silently die on session pause/resume — no completion notification, no work recovery
- Add option to hide email address from welcome banner
- [BUG] SSH Remote: `projects` field in remote ~/.claude.json becomes null after desktop restart — jsonl files intact, UI shows 'No messages yet' for every session
- [Bug] Claude Code not applying fixes despite claiming to complete tasks
- billing is unfair and poorly documented
- [BUG] Claude Code on the web: declared plugins inactive on first session, require restart to fully load
- [BUG] Restore from archive deleted sessions instead of restoring them
- [BUG] M365 connector fails with AADSTS50011 in Cowork — localhost vs 127.0.0.1 redirect URI mismatch
- claude agents: workflow slash-commands missing from dispatch-input completion (regression-adjacent to #61424)
- Claude Desktop's Info.plist missing TCC usage strings, blocks all EventKit-based MCP servers
- False-positive safety blocks on self-administered governance amendments — request for owner-authority mode for verified professional users
- [BUG] Stop pushing "AUTO"-mode
- [DOCS] Plugin marketplace guide omits `skipLfs` option for git-based sources
- [DOCS] MCP docs omit combined startup notification for MCP server and connector authentication
- [DOCS] Agent view docs omit macOS Privacy & Security identity for background agents
- [DOCS] Npm update docs do not explain release-channel behavior for `claude update`
- [DOCS] Agent SDK docs omit `subagent_type: "claude"` worktree and output persistence behavior
- [DOCS] Background session docs omit `$CLAUDE_JOB_DIR` temp-file behavior
- [FR] mask env-var values in 'claude mcp get <server>' output
- [FR] subagent worktrees should not inherit stale local 'user.email' from prior dispatches
- [BUG] Windows: Grep tool leaks rg.exe + conhost.exe processes (~2000 zombies / 14 GB RAM in long sessions)
- [BUG] Stats dashboard "Peak hour" appears off by one hour
- [BUG] Diff highlight (teal SGR background) bleeds past changed text in 2.1.150–2.1.153
- [FEATURE] confirm before deleting session
- Plugin PostToolUse hooks still silently skip in Claude Desktop / Cowork (re-filing closed #51904)
- /code-review skill: silent fallback to main...HEAD reviews other people's commits, and JSON-only output is hard to read
- Monitor tool doesn't source the shell snapshot like Bash does; PATH-dependent tools (jq, sleep, etc.) fail in Monitor commands on macOS/Nix
- [Bug] Long input lines truncated with ellipsis while typing instead of wrapping in terminal UI
- [FEATURE] VS Code extension: Render submitted user messages as Markdown in chat
- OSC 52 copy from Claude TUI doesn't reach clipboard inside tmux (regression in 2.1.146–2.1.153)
- [BUG] RemoteTrigger create/update returns HTTP 400 with circular error: "event_type is required" / "unknown field event_type"
- [BUG] Option to hide or minimize the built-in "status footer" (multi-line debug/cost panel) [re-raise of #31475]
- [Bug] Feedback submissions being closed without review or action
- [FEATURE] Word-jump cursor navigation in Chat input (option+arrow / bindable actions)
- [FEATURE] ! shell mode: filesystem tab completion
- [BUG] API Error: Usage credits required for 1M context
- claude agents: OSC 52 clipboard emission broken in tmux (regression in 2.1.146–2.1.153)
- CLI crashes on macOS 15 M3 - exit code 1
- [FEATURE] Support Cmd+V image paste from clipboard
- [FEATURE] Enhance claude.ai M365 connector to support MS Planner
- [BUG] Slash command autocomplete hijacks pasted absolute file paths starting with /
- PreToolUse hook `if` filter false-positives on complex Bash commands
- [BUG] Diff panel hangs/whites out
- Feature Request: Support drag-and-drop for binary documents (.wps, .doc, .docx, .xlsx, .pdf) in VS Code extension
- [BUG] activation of 1M context in VSCode
- [FEATURE] Support i18n / language localization for built-in slash command outputs
- Ctrl+V para colar imagens deixou de funcionar no CLI (Windows, PowerShell)
- [FEATURE] Please add Norwegian (Bokmål/Nynorsk) language support to the Claude Code interface
- [BUG] OTel log events (claude_code.user_prompt, api_request_body, tool_decision, hook_execution_complete) emitted with empty trace_id/span_id while sibling spans correlate correctly
- [BUG] Cowork crashes on every message, no VM logs generated, missing AppData\Roaming\Claude
- [FEATURE] first-class session handoff + per-session token budgets for unattended runs
- [FEATURE] Smart paste: convert clipboard code to file reference chips (like Cursor)
- [Feature Request] Restore chat pin functionality to title chat submenu
- [BUG] SIGILL issues with version 2.1.153
- [BUG] Cowork plugin upload fails with generic "Plugin validation failed" when a `description` field in any SKILL.md frontmatter contains angle brackets (`<…>`)
- [BUG] Desktop App 2.1.144+: startup scanner deletes cliSessionId from claude-code-sessions local files on every launch — session not found on disk
- [Feature Request] Add keyboard shortcut to copy last message with proper formatting
- [MODEL] Opus 4.7 not 1M
- Allow naming/renaming background agents in `claude agents` view
- Stale worktrees in .claude/worktrees/ are never cleaned up, consuming massive disk space
- Agent worktrees are never cleaned up, silently consuming disk space
- Subagent worktrees not auto-cleaned when reviewer writes scratch files
- [Bug] Skill initialization hangs for extended duration in Plan Mode
- Claude Desktop writes malformed registry Run entry (nested escaped quotes) - crashes Windows Task Manager and other Run-key parsers
- IME candidate window shows at bottom-right corner instead of caret position (Windows CMD)
- [BUG] Pressing 'Escape' doesn't close the /BTW conversation when the main conversation is asking for approval
- [BUG] Opus 4.7 (1M) intermittently emits empty-string values for tool_use.input fields, killing the session
- FleetView agent UI shows "running" with incrementing elapsed time after agent has returned
- /doctor flags context-scoped cmd+c binding as macOS conflict (false positive)
- [BUG] Text Rendering in Elvish
- Desktop app: Bypass Permissions mode flips to Accept Edits on first prompt (M5 / macOS 26.5)
- [Workaround] Date-Weekday Verification Hook — Prevents Claude from writing wrong weekdays
- [BUG] Claude Code create c:/memfs directory without asking me.
- [BUG] Claude Code's Bash execution waits forever with no processes running
- [BUG] usage stays stuck waiting for 5 hr limit after upgrading to premium seat in team plan
- [Workflow tool] resume cache is unreachable for nontrivial workflows because LLM dispatchers can't transcribe args byte-exactly
- Code review (Preview): "Add a repository" shows no results for private GitHub org repos
- [BUG] /context commands blows up context
- [Feature Request] Add precache expiry hook to enable proactive compaction before token eviction
- [BUG] Context indicator shows 0% at session start despite ~20K+ tokens already loaded
- [Feature Request] Add semantic search for --resume session history
- [Feature Request] Add session search, tagging, and filtering capabilities
- [BUG] Cowork Dispatch reports "desktop not available" on Windows 11 while standard Cowork works normally
- [Bug] Claude Code provides incorrect suggestions with high confidence despite errors
- defaultMode: acceptEdits silently overrides per-path permissions.ask rules for Write/Edit
- [FEATUR configurable tip interval (e.g. tipIntervalSeconds: 30 in settings)E]
- Plugin marketplace fails to load: schema rejects 'displayName' key (v2.1.153)
- claude agents: in-session copy uses broken OSC 52 path while overview correctly uses tmux buffer
- [BUG] Plugin agent descriptions (and custom agents) load unconditionally into context — no parity with disable-model-invocation for skills
- Crashed ultrareview consumed a free credit despite producing zero findings
- [Bug] Character rendering issue - invisible or missing text display
- [BUG] Cowork: processo Claude Code encerra com código 3 — .claude.json não contém token de autenticação (Windows 11 25H2)
- [BUG] 2.1.153 silently discards tools/list response from rmcp 0.12.0 HTTP MCP server (works in 2.1.152, wire-identical handshake)
- VS Code extension: option to auto-resume last session when reopening a workspace folder
- [Bug] Conversation continuation failure
- [BUG] Cowork crashes every time I start a new chat or attempt to continue an existing one in any project. The error displayed is: "Claude Code è andato in crash
- [Bug] Unannounced quota changes
- Native update/install fails with 'socket connection was closed unexpectedly' behind proxy — undici TLS incompatibility
- [BUG] Session name reverting after manual change
- [BUG] 非正常思考,上下文过长时,一直显示思考,点击interrupt按钮失效
- Honor `tools:` frontmatter when an agent is invoked via `@mention` — strip `Task` only when the agent did not declare it
- macOS TCC popup still recurring on v2.1.153 — "2.1.153" would like to access data from other apps
- Claude Code leaks pty handles — exhausts pseudo-terminals on macOS after long session
- [Bug] Agent fails to execute or respond to user input
- [BUG] Persistent "Expecting value: line 1 column 1 (char 0)" JSON parse error after tool execution
- [Feature Request] Implement proactive unit test coverage recommendations for recurring bugs
- VS Code panel lacks status line + terminal lacks image paste in Codespaces, forcing a tradeoff
- `/powerup` only shows ~10 lessons — allow viewing the full catalog
- [Bug] Context contamination after auto-compact with unrelated email draft of Tejo/Sado Basin
- [Bug] VSCode terminal output displays corrupted text with garbled symbols
- [Feature Request] Add LaTeX/KaTeX math rendering to TUI
- [Bug] Sub-agent PR review results not validated by orchestrating agent
- Subagents on Pro 1M tier: trivial probes pass, real workloads fail at first tool call (probe-vs-workload divergence)
- Path-scoped rules and subdirectory CLAUDE.md not loaded when creating new files matching the pattern
- AskUserQuestion: cancelling during extended thinking poisons the whole session with 400 'thinking blocks cannot be modified' (2.1.153); concurrent prompts overwrite each other
- Ideas Missing from Claude Cowork Menu (Windows)
- [BUG_BOUNTY_SAFE_POC_2026] Prompt Injection RCE Test - Command Execution Proof
- [BUG] Cowork scheduled task: execution history row not showing after successful run
- Resuming an extended-thinking session fails permanently with 400 "thinking blocks cannot be modified" (transcript stores thinking text as empty but keeps signature)
- [Bug] Plugin-registered CwdChanged and FileChanged hooks don't fire (settings.json works) — v2.1.153
- Auto-archive on PR merge / branch delete — clarify autoArchiveSessions semantics or add dedicated opt-out
- `claude mcp add` echoes Authorization header value verbatim to stdout, leaks bearer tokens to terminal and session transcripts
- [BUG] Bug report — /insights skill, Claude Code The /insights skill outputs a malformed file path.
- Plugin slash commands render with '*'-inline format instead of two-column, despite matching official plugin shape
- [Bug] Unexpected long text generation without user input or goal
- [Bug] Thinking blocks causing task progression blocked without user modification
- [BUG] (Critical!) contamination by an unknown session simirlar to the report => [Bug] Context contamination after auto-compact with unrelated email draft of Tejo/Sado Basin #63137
- [Critical] Opus 4.7 Korean output degeneration — Korean grammar itself collapses in long contexts
- [BUG] Title: Autocompact buffer persists across /clear — wastes tokens for irrelevant old context
- [Bug] Auto-Compact loses user input before processing in conversation history
- Feature: per-invocation effort parameter + runtime session-config introspection for skills
- Auto-mode classifier mislabels Azure DevOps vote -5 as "Reject" when denying PR vote actions
- [BUG] Claude Desktop and Claude Code CLI never re-register MCP tools after OAuth 2.1 handshake on a remote HTTP server
- [BUG] Workspace file tags leak across sessions
- [BUG] Ink renderer crashes on Windows 11 build 26200 (Canary) duplicate banners, terminal mode leaks, mid-operation aborts
- [BUG] Claude Code Desktop issue
- PTY master fd leak in Claude desktop app exhausts macOS kern.tty.ptmx_max after ~2-3 days
- [BUG] Claude Code — Session Management after Unexpected Interruption
- [Windows] Cowork OpenTelemetry exporter does not initialize - zero events emitted to any destination, including loopback
- [Bug] Opus 4.7: 400 `thinking blocks ... cannot be modified` on long extended-thinking sessions, triggered by history-altering events (scheduled prompts / parallel tool-call cancellation)
- [BUG] API Error: Server is temporarily limiting requests (not your usage limit) · Rate limited
- Multi-plugin custom marketplace: only first plugin registered in installed_plugins.json, skills don't load
- [BUG] Git push through the SDK's git proxy fan-outs into ~500 GitHub REST API calls, exhausting the 5,000/hour budget after a handful of pushes
- [BUG] Claude took liberties it really shouldn't with my global config
- [BUG] Agent window focus lost after navigating with arrow keys, causing scroll deadlock
- [BUG] `--model` flag silently ignored in interactive sessions (works in `--print` only)
- [BUG] Dispatch permanently shows "desktop appears offline" on Windows 11 - never worked on first use
- feat: support per-command enableWeakerNetworkIsolation as safer alternative to dangerouslyDisableSandbox
- /code-review outputs a raw JSON array instead of readable findings
- [BUG] Cowork — Additional allowed domains ignored on Team plan; same domain works on Pro plan
- Haiku
- [Bug] False positive blocking beneficial outcomes in tool execution
- 3P Bedrock SSO: credentials silently expire without triggering re-auth on day 2+
- CLAUDE_AUTOCOMPACT_PCT_OVERRIDE in settings.json env block silently ignored by autocompact logic
- Auto-compaction deletes main session JSONL before verifying summary completion, causing data loss
- [Bug] Claude Code not executing stated actions or producing expected results
- [FEATURE] Deferred Messages — Queue Input for End of Turn
- [BUG] Up/Down arrows in input box navigate history instead of moving cursor — regression in 2.1.149+
- Cancelling a parallel tool-call batch corrupts thinking blocks -> 400 "thinking blocks cannot be modified" permanently wedges the session
- Claude Code caused data loss, then contradicted itself about recovery (two incidents, one session)
- [Bug] Unclear error messages from Claude Code CLI
- [Bug] Agent tool rejecting due to context size limit exceeded
- claude agents: daemon and bg-spare processes spin at ~100% CPU when idle
- [BUG] Compaction fails with "context window limit" error even when context usage is low (e.g., 20%) — regression in v2.1.153
- Remote Control entitlement lost after May 27-28 incident — `Error: Remote Control is not yet enabled for your account` on active Max subscription
- PreToolUse hook exit code 2 does not block Write tool
- [Bug] Thinking blocks in latest assistant message are immutable
- GUI: dispatch file:// and custom-scheme clicks to OS shell handler
- Show current model in statusLine by default
- [Bug] Agent console becomes unresponsive to keyboard input after multiple agents initialized
- [FEATURE] PreToolUse hooks should have a way of updating the environment
- [Bug] Unable to start or use Claude Code CLI
- [BUG] Repository not visible in Claude Code web repo picker
- Session permanently wedged on 400 "thinking blocks cannot be modified" after parallel tool_results
- [Bug] @ autocomplete loses sibling repos after a file edit in multi-repo workspace
- Unclear error message when creating sub-agent without authentication
- [Bug] Anthropic API errors causing frequent failures and high token usage
- [BUG] @ mention file picker only shows packages, not individual files (desktop app - Code tab)
- [Bug] TUI panel footer remains sticky and consumes excessive terminal space
- PR-status polling exhausts GitHub GraphQL rate limit on repos with many open PRs
- [BUG] Windows: welcome panel not shown in some project folders (2.1.153)
- [Bug] Anthropic API Error: thinking blocks corrupted during context compaction with extended thinking enabled
- API 400 "thinking blocks cannot be modified" permanently bricks session during agent activation (interleaved thinking + tool use)
- Right-click Copy copies the whole message instead of the selection; pasted text retains dark background
- Mid-session model switch corrupts conversation when extended thinking is enabled (API 400: 'thinking blocks cannot be modified')
- [BUG] Markdown file links in chat output do not open files when clicked (VS Code extension)
- Stuck retry loop: `400 thinking blocks cannot be modified` on large interleaved-thinking turns using AskUserQuestion
- [FEATURE] Prompt user for approval before auto-compaction proceeds
- Custom MCP connectors not attachable to scheduled routines — no UUID discovery path
- [BUG] Claude in Chrome — Navigation blocked for teams.cloud.microsoft and outlook.cloud.microsoft after Microsoft domain migration**
- [BUG] Claude Desktop — Personal plugins panel renders list but is entirely non-interactive (macOS, v1.9255.2)
- [Bug] error when using Workflows
- [BUG] Persistent "update available" notification despite being on latest version
- [BUG] Sweep Agent from /code-review never completes
- [Bug] Tool calls not executing or returning results
- [FEATURE] Cloud-synced memory and settings across machines
- [Bug] Terminal UI freezes when Ctrl+O view exits during interactive prompt in plan mode
- Continuous api errors when using claude code with Opus 4.7 with thinking on low
- [Feature Request] Add support for installing and using previous Claude Code versions
- [Bug] Extended Thinking: Summarized thinking blocks fail signature validation when resent to API
- [Bug] Anthropic API Error: 'thinking' blocks cannot be modified
- [Bug] Anthropic API Error: Thinking blocks cannot be modified with extended thinking mode
- Feature request: Lazy/on-demand MCP server connections
- [Bug] Tool Arguments Parsed as String Instead of Object
- [Bug] Anthropic API Error: Insufficient context provided
- [Bug] Claude Opus occasionally uses moskovian(russian) orthography instead of Ukrainian in system-prompted responses
- Opus 4.8: backgrounded task completions (subagents AND Bash) crash with 400 "thinking blocks cannot be modified"
- [Bug] Opus 4.7 fabricates stable preferences ("my default") to rationalize arbitrary choices when challenged
- [Bug] Unable to update Claude Code CLI
- [BUG] Desktop app: /remote-control mints link + connects bridge (main.log) but in-chat link/QR panel never renders
- Feature: sessionColor and sessionName in .claude/settings.json
- [BUG] Anthropic API error: thinking blocks
- [FEATURE] Support Remote MCPs in Cowork as in Claude Code
- [Bug] Anthropic API Error: 400 Bad Request with Redacted Thinking - 0 4.7 & 4.8
- [Bug] Anthropic API Error: Cannot modify thinking blocks from different model versions
- Interleaved thinking + multi-tool turn corrupts thinking block (text blanked, signature kept) → permanent 400 'blocks must remain as they were'
- [BUG] Mode/permission changes mid-tool-loop (effortLevel: xhigh) poisons entire session
- Session failure log: Opus 4.6 ignores its own rules for an entire session
- [BUG] "400 Guardrail was enabled" error when using Claude Opus 4.8 with AWS Bedrock
- [Feature Request] Add subagent approach selection option to avoid accidental feedback
- Persistent 400 'thinking blocks in the latest assistant message cannot be modified' — interleaved thinking persisted with empty text + signature bricks sessions
- [BUG] DesktopvsApp
- [BUG] Opus 4.7 cache hit rate collapse after May 27 incident — Messages 1.1k→88.9k in 9 minutes, $630/session
- [Bug] Anthropic API Error: Invalid thinking block format
- [BUG] FUCK CLAUDE
- Opus 4.8 extended thinking: Stop hook block re-entry corrupts thinking blocks → 400
- [Bug] 4.8 Fails when accessing previous model history
- [Bug] Unintended File Modifications During Execution
- [DOCS] Model configuration docs omit lean system prompt default scope and model exceptions
- Add "Always allow globally" option to permission prompts
- Server-side model upgrade (Opus 4.7→4.8) wedges in-flight sessions with `thinking blocks cannot be modified` 400
- [DOCS] AskUserQuestion docs missing multiple-choice prompt decision threshold
- [DOCS] Agent view docs omit shell-command background session launch syntax
- [DOCS] Agent view dispatch input docs incorrectly imply `/logout` dispatches as a prompt
- [DOCS] Claude in Chrome docs omit connected-browser selection behavior
- [DOCS] Plugin docs omit `defaultEnabled: false` for opt-in plugins
- Feature Request: Customizable chat text colors for user and assistant messages
- [DOCS] `/plugin` Discover tab docs omit directory-based suggested plugin pins
- VSCode Chrome integration silently fails: 3 distinct bugs
- [DOCS] MCP stdio docs omit session environment variables
- [Bug] Anthropic API error on second request within session with Claude Opus 4.8
- Cowork emits a blank session "index" handoff on focus when a CLI session is paused awaiting input
- [DOCS] MCP docs omit `claude mcp list/get` pending-approval output for unapproved project servers
- [BUG] /compact fails with 400 error when last assistant turn contains thinking blocks
- [DOCS] `/claude-api` docs omit Opus 4.8 migration guidance
- [DOCS] Fast mode docs still recommend deprecated Opus 4.6 override variable
- [DOCS] Bash tool docs omit `$TMPDIR` consistency across sandboxed and unsandboxed commands
- [Bug] Anthropic API Error: 400 Bad Request on Extended Thinking
- [DOCS] Background session docs omit worktree-isolation behavior for spawned subagents
- Built-in mechanistic self-verification of verifiable claims (symmetric to the auto permission gate)
- [DOCS] Worktree docs do not clarify `worktree.baseRef: "head"` inside linked worktrees
- [BUG] Excessive RAM usage with multiple parallel chats (~10 sessions → 30 GB memory pressure, macOS OOM)
- [DOCS] Managed MCP policy docs omit invalid `allowedMcpServers`/`deniedMcpServers` entry behavior
- [DOCS] Effort docs omit `CLAUDE_CODE_ALWAYS_ENABLE_EFFORT` unsupported-model behavior
- Regression (2.1.147–2.1.150?): resuming an extended-thinking session after a CC update/model-switch → unrecoverable 400, session bricked
- [DOCS] Windows updater docs omit `claude.exe` in-use recovery guidance
- [DOCS] VS Code auto mode docs still tie mode-picker visibility to bypass-permissions setting
- [DOCS] MCP docs omit `/mcp` tool list and detail rendering behavior
- [DOCS] Fine-grained tool streaming docs still describe provider opt-in behavior
- bypassPermissions: session startup reads flat pref, GUI toggle writes per-account pref — they never sync
- [BUG] Claude Desktop Code tab causes disk write limit violation — 8.5GB in 11 min, macOS kills app (M5, v1.9659.1)
- Ultrareview v2.1.96: docs describe /tasks command + claude ultrareview --json subcommand that don't exist; findings hard to read after completion
- I'd be happy to help create a GitHub issue title, but I don't see the error message in your message. Could you please share the specific error you're encountering? That way I can generate an accurate and descriptive issue title for you.
- [BUG] Claude in Chrome `file_upload` rejects all scheduled-task sessions with misleading error (real cause: INVALID_SESSION)
- Extended thinking: signed thinking block 'cannot be modified' (400) permanently wedges session
- RTL text support for Hebrew (and Arabic) in Claude Code
- [Bug] Random errors occurring across multiple operations