Skip to content

rondagdag/mission-control-agent

Repository files navigation

Sentinel NASA CLI - Custom Claude Skill

This project demonstrates a custom Claude skill approach for CLI tool integration, where structured tool definitions wrap CLI commands instead of using the generic bash tool.

Architecture

User Request
    ↓
Claude Agent (agent.py)
    ↓
Custom Sentinel Skill (sentinel_skill.py)
    ├─ sentinel_find_closest tool
    └─ sentinel_get_visual tool
        ↓
    Sentinel CLI (sentinel/)
        ↓
    NASA APIs

Why Custom Skills vs Bash Tool?

Approach Benefits Drawbacks
Custom Skill (this project) ✅ Type-safe tool inputs
✅ Semantic tool names
✅ Input validation before execution
✅ Better Claude understanding
⚠️ Requires wrapper code
Bash Tool (generic) ✅ Simple, no wrapper
✅ Works with any command
⚠️ No input validation
⚠️ Agent constructs commands manually
⚠️ Less semantic clarity

Files

  • sentinel_skill.py: Custom tool definitions and executor

    • SENTINEL_TOOLS: Tool schemas for Claude
    • SentinelSkillExecutor: Wraps CLI command execution
    • create_tool_handler(): Factory for tool handler function
  • agent.py: Example agent using the custom skill

    • Uses SENTINEL_TOOLS instead of bash tool
    • Handles tool execution loop
    • Interactive CLI interface
  • sentinel/: CLI implementation

    • Typer-based CLI commands
    • Returns JSON output via --json flag
    • Automatically loads .env file for NASA_API_KEY

Installation

# Install with UV (recommended)
uv pip install -e ".[agent]"

# Or with pip
pip install -e ".[agent]"

# Configure API keys
cp .env.example .env
# Edit .env and add your API keys:
#   NASA_API_KEY=your_nasa_key_here
#   ANTHROPIC_API_KEY=your_anthropic_key_here

# Both the CLI and agent will automatically load from .env file

Note: The project uses python-dotenv to automatically load .env file. You don't need to manually export environment variables if you use the .env file approach.

Usage

Run the Agent

python agent.py

Example interaction:

You: What's the closest asteroid today?
Agent: The closest asteroid today is 2024 BX1, approaching at 2,340,000.5 miles...

You: Show me NASA's image from last week
Agent: Here's the Astronomy Picture of the Day...

Use the Skill in Your Code

from sentinel_skill import SENTINEL_TOOLS, create_tool_handler
import anthropic

client = anthropic.Anthropic()
tool_handler = create_tool_handler()

response = client.messages.create(
    model="claude-haiku-4-5-20251001",
    max_tokens=4096,
    tools=SENTINEL_TOOLS,  # Custom sentinel tools
    messages=[{"role": "user", "content": "Find closest asteroid"}]
)

# Handle tool execution
if response.stop_reason == "tool_use":
    for block in response.content:
        if block.type == "tool_use":
            result = tool_handler(block.name, block.input)
            print(result)

Tool Definitions

sentinel_find_closest

Find today's closest asteroid to Earth.

Input Schema:

{
  "verbose": false  // Optional: enable diagnostic output
}

Output:

{
  "status": "success",
  "data": {
    "asteroid": {
      "name": "2024 BX1",
      "distance_miles": 2340000.5,
      "velocity_mph": 25000.3,
      "approach_date": "2024-02-16T14:23:00Z"
    }
  },
  "message": "Found closest asteroid: 2024 BX1"
}

sentinel_get_visual

Get NASA Astronomy Picture of the Day for a date.

Input Schema:

{
  "date": "2024-01-15",  // Optional: YYYY-MM-DD format, defaults to today
  "verbose": false        // Optional: enable diagnostic output
}

Output:

{
  "status": "success",
  "data": {
    "visual": {
      "date": "2024-01-15",
      "url": "https://apod.nasa.gov/apod/image/...",
      "title": "Orion Nebula in Infrared",
      "description": "This stunning image...",
      "media_type": "image"
    }
  },
  "message": "Retrieved image for 2024-01-15"
}

Implementation Notes

Constitutional Compliance

This approach aligns with the project's constitutional principles:

  1. Boundary: Business logic stays in CLI, skill only wraps execution
  2. Output Format: CLI returns structured JSON, skill passes through
  3. Rule of Discovery: Tool schemas serve as explicit contract (better than --help parsing)

Error Handling

The skill catches all exceptions and returns error responses in the standard CLIOutput format:

{
  "status": "error",
  "data": null,
  "message": "Detailed error message here"
}

This ensures Claude always receives structured output, even on failures.

Testing

Test the skill independently:

from sentinel_skill import create_tool_handler

handler = create_tool_handler()

# Test find-closest
result = handler("sentinel_find_closest", {})
print(result)

# Test get-visual
result = handler("sentinel_get_visual", {"date": "2024-01-15"})
print(result)

Next Steps

  1. Implement CLI: Build sentinel/ package with Typer commands
  2. Add Tests: Test skill executor and agent integration
  3. Enhance Tools: Add more parameters (date ranges, filters, etc.)
  4. Deploy: Package for distribution

Documentation

See specs/001-sentinel-nasa-cli/ for complete planning documentation:

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors