Give stations a tool from an HTTP API
The agent gets a command that calls the API, and Spotlight keeps the API key, which the agent never sees. You need:
- Terraform set up with the Spotlight provider, using a token that has the
configureandsecretsscopes. See Manage Spotlight with Terraform. - A key for the API.
- A Spotlight deployment that allows outbound calls to the API's host, since Spotlight calls the API from its own servers.
If the API publishes an OpenAPI description or a GraphQL schema, see Generate tools from an API description instead.
The example uses a placeholder API at api.acme.example that takes a comment
as a JSON POST to /comments. Put your own API's host, path and body in its
place.
Keep the API key as a secret
Bind the secret to the API's host, in the header and with the prefix the API expects. Spotlight sends it to that host only, over HTTPS.
variable "acme_api_key" {
type = string
sensitive = true
}
data "spotlight_workspace" "acme" {
slug = "acme"
}
resource "spotlight_secret" "acme_api_key" {
workspace_id = data.spotlight_workspace.acme.id
name = "ACME_API_KEY"
bindings = [
{ host = "api.acme.example", carrier = "header", name = "authorization", prefix = "Bearer " },
]
value_wo = var.acme_api_key
value_wo_version = 1
}To rotate the key later, give the new value and raise value_wo_version.
If the API reads the key from the query
Some APIs, such as Google Maps, take the key as a query parameter. Bind the
secret with carrier = "query" and the parameter's name:
resource "spotlight_secret" "maps_key" {
workspace_id = data.spotlight_workspace.acme.id
name = "MAPS_KEY"
bindings = [
{ host = "maps.googleapis.com", carrier = "query", name = "key" },
]
value_wo = var.maps_key
value_wo_version = 1
}Leave the key out of the request's url and name only the secret, as in
auth = { secrets = ["secret.MAPS_KEY"] }. For how Spotlight sets the
parameter and keeps the key out of what it records, see
Bindings.
Define the action and the tool
Write the request as an action, and offer it to agents as a tool: does
names the action, description tells the agent when to use it, and each input
becomes a flag. In the request, read the inputs as inputs.<name> and name the
secret in auth.secrets.
data "spotlight_team" "core" {
workspace_id = data.spotlight_workspace.acme.id
key = "core"
}
resource "spotlight_integration" "acme" {
team_id = data.spotlight_team.core.id
definition = {
integration = "acme"
actions = {
comment = {
request = {
method = "POST"
url = "https://api.acme.example/comments"
body = {
issue = "$${{ inputs.issue }}"
text = "$${{ inputs.body }}"
}
auth = { secrets = ["secret.${spotlight_secret.acme_api_key.name}"] }
}
}
}
tools = {
comment = {
does = "comment"
description = "Comment on the issue."
inputs = {
issue = { type = "string", required = true }
body = { type = "string", required = true }
}
}
}
}
}An input is text unless you say otherwise. For a number, give it
type = "integer" or type = "number", and for a flag that is on or off,
type = "boolean". For a list or an object, give its JSON Schema as schema
in place of type; the agent then passes it as JSON:
labels = { schema = { type = "array", items = { type = "string" } } }If the API names a field team_id or teamId, name the input the same way:
an input name may hold letters, digits, _ and -.
Give the tool to a station
Add the tool to the station's tools in the line. Name it through the
integration's tools map, so renaming or removing the tool fails the plan
here:
station {
key = "implementation"
name = "Implementation"
harness = "claude-code"
tools = [spotlight_integration.acme.tools["comment"]]
passes_to = ["code-review"]
}Outside Terraform, the name is <integration>.<tool>, as in acme.comment.
Run terraform apply. The next run at that station has the tool. Its agent
calls it as a command:
spotlight acme comment --issue ACME-42 --body "Fixed in the linked pull request."spotlight tools lists the tools a run was given, with their flags.
spotlight tools describe acme.comment prints one with its inputs and an
example call.
See what a tool answers with
After a call to the tool succeeds, Spotlight learns the shape of its answer:
the field names and their types, never the values. In runs that start after
that call, spotlight tools describe prints it under
Answers with (learned from earlier calls, may be incomplete):, so the agent
knows which fields to read. Each later successful call adds to it. Redefining
or removing the integration, and disbanding the team, forgets what was
learned. See
Learned output.
If a person should agree before each call, see Require approval before a tool runs.
Related
spotlight_integration: every field of an action and a tool.spotlight_secret, for binding options.- Agent commands