diff --git a/README.md b/README.md index f7b1c53..0f6ce22 100644 --- a/README.md +++ b/README.md @@ -63,7 +63,27 @@ curl -X POST http://localhost:8072/batch/lint \ ### Production (Pre-built Images) -See `atomic-pumpkin-deploy` for production deployment using GHCR images. +```bash +# Pull pre-built images from GitHub Container Registry +docker pull ghcr.io/real-wimpsquad/code-thumbs:latest +docker pull ghcr.io/real-wimpsquad/code-thumbs-api:latest + +# Run with docker-compose +docker-compose up -d + +# Or run directly +docker run -d --name code-thumbs \ + -v $(pwd):/workspace \ + ghcr.io/real-wimpsquad/code-thumbs:latest \ + tail -f /dev/null + +docker run -d --name code-thumbs-api \ + -p 8072:8072 \ + -v $(pwd):/workspace \ + -v /var/run/docker.sock:/var/run/docker.sock \ + -e CODE_THUMBS_CONTAINER=code-thumbs \ + ghcr.io/real-wimpsquad/code-thumbs-api:latest +``` ## API Endpoints @@ -94,8 +114,9 @@ Batch response format: `path1|result1\n---\npath2|result2` - `GET /` - API overview - `GET /health` - Health check (includes tool availability) -- `GET /languages` - List supported languages and tools -- `GET /tools/openai` - OpenAI function schemas (structured format) +- `GET /languages` - List supported languages and tools (verbose JSON) +- `GET /tools` - **Compressed tool specs (ml-exclusive format for agents)** +- `GET /tools/openai` - OpenAI function schemas (verbose JSON for OpenAI integration) ## ML-Exclusive Response Format @@ -170,6 +191,35 @@ err:timeout|code:504|msg:tool_execution_timed_out All responses (success + error) use compressed format with `{"result": "..."}` wrapper. +## Agent Tool Discovery + +**For AI agents:** Use `GET /tools` endpoint for compressed tool specification: + +```bash +curl http://localhost:8072/tools +``` + +Returns ml-exclusive compressed format: +```json +{ + "system": "code_thumbs", + "endpoints": { + "file_ops": "POST/format/file{path,lang?,tool?}→read+fmt+write|...", + "content_ops": "POST/format{lang,content,tool?,check_only?}→fmt|...", + "batch_file": "POST/batch/format/files{paths[],lang?,tool?}→multi_fmt|...", + "meta": "GET/health→status|GET/languages→17lang_list|..." + }, + "languages": "py→ruff,black,pylint,mypy|js/ts→prettier,eslint,tsc|...", + "philosophy": "agent_first→prefer_file_ops_over_content→atomic_operations→...", + "usage": { + "recommended": "POST/format/file{path}→1_call_atomic", + "legacy": "Read→POST/format{content}→parse→Write→5_steps_avoid" + } +} +``` + +**Philosophy:** LLM-first design → semantic density → compressed syntax → direct file operations + ## MCP Server Located in `mcp-server/mcp_server_code_thumbs.py`. Example configuration (Claude Desktop): @@ -209,6 +259,30 @@ Client → API (port 8072) → Docker exec → code-thumbs container (tools) - `/health` endpoint shows tool availability status - 30s timeout per operation to prevent hangs +## Integration + +### Atomic Pumpkin (Optional) + +Code Thumbs can be used as an addon with [Atomic Pumpkin](https://github.com/real-wimpsquad/atomic-pumpkin): + +```bash +make dev ADDONS="code-thumbs" +``` + +This mounts the atomic-pumpkin workspace at `/workspace` for formatting/linting project files. + +### Standalone + +Code Thumbs works independently - just mount your project directory to `/workspace`: + +```bash +docker run -d --name code-thumbs-api \ + -p 8072:8072 \ + -v /path/to/your/project:/workspace \ + -v /var/run/docker.sock:/var/run/docker.sock \ + ghcr.io/real-wimpsquad/code-thumbs-api:latest +``` + ## License MIT - See LICENSE file diff --git a/src/api_code_thumbs.py b/src/api_code_thumbs.py index 24507c8..aee57bb 100644 --- a/src/api_code_thumbs.py +++ b/src/api_code_thumbs.py @@ -613,6 +613,7 @@ async def root(): "version": "1.0.0", "endpoints": { "GET /languages": "List supported languages and tools", + "GET /tools": "Compressed tool specs (ml-exclusive format)", "POST /format": "Format code (content)", "POST /lint": "Lint code (content)", "POST /fix": "Auto-fix issues (content)", @@ -624,7 +625,7 @@ async def root(): "POST /batch/format/files": "Format multiple files by path", "POST /batch/lint/files": "Lint multiple files by path", "POST /batch/fix/files": "Fix multiple files by path", - "GET /tools/openai": "OpenAI function schemas", + "GET /tools/openai": "OpenAI function schemas (verbose)", "GET /docs": "Interactive API docs (Swagger)", "GET /redoc": "API documentation (ReDoc)", }, @@ -700,6 +701,35 @@ async def list_languages(): } +@app.get("/tools") +async def agent_tools(): + """Agent-discoverable tools in compressed ml-exclusive format""" + return { + "system": "code_thumbs", + "version": "1.0.0", + "compressed": "ml_exclusive_format→max_semantic_density", + "endpoints": { + "file_ops": "POST/format/file{path,lang?,tool?}→read+fmt+write|POST/lint/file{path,lang?,tool?}→read+lint+report|POST/fix/file{path,lang?,tool?}→read+fix+write|POST/check/file{path,lang?,tool?}→read+check+report", + "content_ops": "POST/format{lang,content,tool?,check_only?}→fmt|POST/lint{lang,content,tool?}→issues|POST/fix{lang,content,tool?}→fixed|POST/check{lang,content}→fmt+lint", + "batch_file": "POST/batch/format/files{paths[],lang?,tool?}→multi_fmt|POST/batch/lint/files{paths[],lang?,tool?}→multi_lint|POST/batch/fix/files{paths[],lang?,tool?}→multi_fix", + "batch_content": "POST/batch/format{lang,files:[{path,content}],tool?}→multi_fmt|POST/batch/lint{lang,files:[{path,content}],tool?}→multi_lint|POST/batch/fix{lang,files:[{path,content}],tool?}→multi_fix", + "meta": "GET/health→status|GET/languages→17lang_list|GET/tools→this|GET/tools/openai→verbose_schemas", + }, + "languages": "py→ruff,black,pylint,mypy|js/ts→prettier,eslint,tsc|go→gofmt,goimports,golangci-lint|rust→rustfmt,clippy|c/cpp→clang-format,clang-tidy|cs→csharpier,dotnet-format|java→google-java-format,checkstyle|kt→ktlint|swift→swiftformat|php→php-cs-fixer,phpstan|rb→rubocop|sh→shfmt,shellcheck|sql→sqlfluff|md→prettier,markdownlint|yaml→prettier,yamllint", + "response_format": "compressed→tool:ruff|changed:yes\\n\\n{code}|errors→err:type|code:NNN|msg:compressed", + "workspace": "/workspace→mounted_project_root", + "lang_detection": "auto_via_extension→.py=python,.ts=typescript,.go=go", + "philosophy": "agent_first→prefer_file_ops_over_content→atomic_operations→auto_detect_lang→compressed_responses", + "usage": { + "recommended": "POST/format/file{path}→1_call_atomic", + "legacy": "Read→POST/format{content}→parse→Write→5_steps_avoid", + "batch": "POST/batch/format/files{paths[]}→efficient_multi", + }, + "health": "GET/health→{status,container,tools:{ruff:available,...}}", + "tools_available": "17lang|35+tools|format+lint+fix→see_GET/languages_for_detail", + } + + @app.post("/format") async def format_code(req: FormatRequest): """Format code using specified or default formatter"""