The official Python SDK for building Chitty Workspace marketplace packages.
Replaces the duplicate auth.py and config.py files that every package used to copy. One install, all the helpers you need.
pip install chitty-sdkFor HTTP helpers (uses requests under the hood):
pip install chitty-sdk[http]The HTTP module falls back to urllib automatically when requests is not installed, so the extra is optional.
#!/usr/bin/env python3fromchitty_sdkimporttool_main, require_google_token, api_get@tool_maindefmain(args):
token=require_google_token()
messages=api_get(
"https://gmail.googleapis.com/gmail/v1/users/me/messages",
token=token,
params={"q": "in:inbox", "maxResults": "10"},
)
return {"emails": messages.get("messages", [])}That is a complete, working tool script. The @tool_main decorator handles reading JSON from stdin, writing the response to stdout, and catching exceptions.
Credentials are resolved in order: environment variable CHITTY_CRED_{KEY}, then OS keyring.
fromchitty_sdkimportget_credential, require_credential# Returns None if not foundapi_key=get_credential("my_service_api_key")
# Prints error JSON and exits if not foundapi_key=require_credential("my_service_api_key")Provider shortcuts:
fromchitty_sdkimportget_google_token, require_google_tokenfromchitty_sdkimportget_slack_token, require_slack_tokentoken=require_google_token() # or exits with errortoken=get_slack_token() # or NoneRead feature flags and resource allow-lists from CHITTY_PACKAGE_CONFIG.
fromchitty_sdkimportload_config, check_feature, require_featurefromchitty_sdkimportget_allowed_resources, check_resource, require_resource# Load raw configconfig=load_config()
# Feature flags (default to True when not configured)ifcheck_feature("allow_send_message"):
send_it()
# Exit with error if feature is disabledrequire_feature("allow_delete")
# Resource allow-listsbuckets=get_allowed_resources("buckets") # [] means all allowedifcheck_resource("channels", "general"):
post_to_channel()
# Exit with error if resource is not allowedrequire_resource("channels", "secret-ops")Standard stdin/stdout JSON protocol for tool scripts.
fromchitty_sdkimportread_input, success, errorargs=read_input() # Parse JSON from stdinsuccess({"key": "val"}) # Print success JSON, exit(0)error("Something broke") # Print error JSON, exit(0)The @tool_main decorator combines all three:
fromchitty_sdkimporttool_main@tool_maindefmain(args):
ifnotargs.get("name"):
return {"error": "name is required"}
return {"greeting": f"Hello, {args['name']}!"}Note: error() and require_* functions exit with code 0, not 1. Tool errors are data for the LLM, not process crashes.
Authenticated API calls with automatic JSON parsing.
fromchitty_sdkimportapi_get, api_post, api_put, api_deletefromchitty_sdk.httpimportChittyApiError# GET with bearer auth and query paramsdata=api_get("https://api.example.com/items", token="...", params={"limit": "10"})
# POST with JSON bodyresult=api_post("https://api.example.com/items", token="...", json_data={"name": "New Item"})
# PUTapi_put("https://api.example.com/items/123", token="...", json_data={"name": "Updated"})
# DELETEapi_delete("https://api.example.com/items/123", token="...")
# Error handlingtry:
data=api_get("https://api.example.com/secret", token="bad-token")
exceptChittyApiErrorase:
print(f"Status {e.status_code}: {e.body}")For scripts that maintain a long-running connection (e.g. Slack Socket Mode).
fromchitty_sdkimportsend_ready, send_heartbeat, send_eventfromchitty_sdkimportsend_log, send_error, read_platform_message# Notify the platformsend_ready("Connected to Slack workspace Acme Corp")
# Keep-alivesend_heartbeat()
# Deliver an event for agent processingsend_event("mention", {"user": "U123", "text": "hello", "channel": "C456"})
# Loggingsend_log("Processing event", level="info")
send_error("Token expired", fatal=True)
# Read a platform message (non-blocking, 1s timeout)msg=read_platform_message(timeout=1.0)
ifmsgandmsg.get("type") =="shutdown":
cleanup()#!/usr/bin/env python3fromchitty_sdkimporttool_main, require_slack_token, check_feature, check_resource, api_post, error@tool_maindefmain(args):
token=require_slack_token()
channel=args.get("channel", "").lstrip("#")
text=args.get("text", "")
ifnotchannelornottext:
error("Both 'channel' and 'text' are required.")
ifnotcheck_feature("allow_send_message"):
error("Sending messages is disabled in package configuration.")
ifnotcheck_resource("channels", channel):
error(f"Channel '{channel}' is not in the allowed channels list.")
result=api_post(
"https://slack.com/api/chat.postMessage",
token=token,
json_data={"channel": channel, "text": text},
)
ifnotresult.get("ok"):
error(result.get("error", "Unknown Slack API error"))
return {"channel": result["channel"], "ts": result["ts"], "message": f"Sent to #{channel}"}Full documentation at chitty.ai/docs/sdk.
MIT