김인턴
API

Invoking tools

List the tools, call one, and read what actually changed.

Listing tools

curl https://api.intern.kim/v1/tools \
  --header "Authorization: Bearer $INTERNKIM_TOKEN"

The response is {"tools": [...]}, holding the full descriptor of every tool the key's permission can call, and a catalog field saying which list you got. The base catalog is answered without asking the company machine, so it is the fast one and it is the same for everyone; it is also documented on the tool catalog page. Whether a tool can run right now is known only on the machine, and tools that come and go with a companion are not in the base list at all. Ask for those with ?live=true, which costs the round trip. X-INTERNKIM-CATALOG says base on either discovery answer.

Reading a descriptor

curl https://api.intern.kim/v1/tools/task_add \
  --header "Authorization: Bearer $INTERNKIM_TOKEN"

A tool the token cannot call answers 404 here, as if it did not exist. The descriptor fields worth reading before a call:

FieldSays
inputSchemathe JSON Schema your input must satisfy
outputSchemathe shape of result on success
sideEffectClasswhich scope rank the call requires
idempotencywhether idempotencyKey means anything for this tool
resultContract.effectswhich effects entries a successful call promises
availabilitywhether the tool can run right now, and why not

Invoking

curl https://api.intern.kim/v1/tools/task_add/invoke \
  --header "Authorization: Bearer $INTERNKIM_TOKEN" \
  --header 'Content-Type: application/json' \
  --data '{"input":{"title":"draft the quarterly report","size":"M"}}'

The body carries input and, where supported, idempotencyKey. Anything else you send for actor or context is overwritten from the token before the request leaves the gateway; the test TestPublicToolGatewayOverridesActorFromBearerToken pins this down.

No approval pause

In a messenger conversation the agent stops and asks before a delete or a send. The gateway marks every non-read invocation as an already-approved continuation, so the same tools act immediately here. The scope on the token is the consent: a destructive token deletes without a question.

The response

{
  "provider": "internkim",
  "selectedBackend": "device",
  "toolName": "task_add",
  "outcome": "succeeded",
  "status": "created",
  "effects": [
    { "objectType": "task", "effect": "created", "id": "..." }
  ],
  "result": { "taskID": "...", "title": "draft the quarterly report" }
}
FieldMeaning
provider, selectedBackendwhere the call ran: device, companion, or remote
outcomesucceeded, failed, or denied
statusa tool-specific status string
effectsthe record of what changed
resultthe tool's output, matching its outputSchema
isError, message, errorCode, failureStagefailure detail
retryable, safeRetrywhether a retry is sensible, and whether it is safe

Effects

effects is the record of what actually changed, written by the runtime from the tool's result contract. Each entry names an objectType, an effect (created, updated, deleted, ...), and one identity: an id, a path, or a url. Some entries add visibility, durability, filename, contentType, or a summary.

Verify through effects, not through result. An empty effects list means nothing changed, whatever the result text says.

Idempotency

idempotencyKey is honored only where the descriptor's idempotency.supported is true. In the base catalog that is message_send; everywhere else the key is carried but changes nothing. For agent messages, messageID deduplicates instead.

Choosing a target with a hint

Mutating tools take no separate ID parameter. task_update and task_delete take a taskHint: the exact task ID, or the exact current title as a task_list result shows it. Never the new or intended title. The server resolves the hint deterministically; when it does not resolve to exactly one task, the call fails and returns the list of matching candidates to retry against. It never guesses.

Person references work the same way: participantPersonHints takes names, @handles, or emails.

End to end

With a write token from Getting a token:

curl https://api.intern.kim/v1/tools/task_add/invoke \
  --header "Authorization: Bearer $INTERNKIM_TOKEN" \
  --header 'Content-Type: application/json' \
  --data '{"input":{"title":"draft the quarterly report","size":"M"}}'

curl https://api.intern.kim/v1/tools/task_update/invoke \
  --header "Authorization: Bearer $INTERNKIM_TOKEN" \
  --header 'Content-Type: application/json' \
  --data '{"input":{"taskHint":"draft the quarterly report","status":"in_progress"}}'

The first response's effects carries {"objectType":"task","effect":"created","id":...}; the second carries the same task with "effect":"updated". Deleting it takes a destructive token:

curl https://api.intern.kim/v1/tools/task_delete/invoke \
  --header "Authorization: Bearer $INTERNKIM_TOKEN" \
  --header 'Content-Type: application/json' \
  --data '{"input":{"taskHint":"draft the quarterly report"}}'

With only write, this answers 403 tool is not available for this token before anything reaches capabilityd.

Where it is implemented

ConcernWhere
List, read, invoke handlerswritePublicTools, writePublicTool, invokePublicTool in internal/admind/public_tool_gateway.go
Descriptor fetch from capabilitydfetchCapabilityRegistry over the unix socket; device and companion descriptors are merged in exposableCapabilityDescriptors
The actor overrideinvokePublicTool sets Actor, Context, PrivacyClass, RequiresUserPresence after decoding your body
The approval-continuation flagpublicToolInvokeContext, keyed on publicToolScopeForDescriptor
Request and response typesToolInvokeRequest, ToolInvokeResponse, ResourceEffect in pkg/capabilityprotocol/protocol.go
Input and output schemaspkg/capabilityprotocol/generated/capability-tools.json

On this page