A code-based UI for exploring and calling gRPC and Twirp APIs.
Write TypeScript to construct requests, call services, and inspect responses — no forms, no clicking through fields.
- Code-based — Write TypeScript to call your APIs. Full autocomplete for services, methods, and message fields.
- gRPC & Twirp — Native support for both protocols. Reads your
.protofiles or uses gRPC server reflection. - macOS & Docker — Available on the Mac App Store or as a Docker container for any environment.
docker run --pull always --name kaja -d -p 41520:41520 \
-v /my_app/proto:/workspace/proto \
-v /my_app/kaja.json:/workspace/kaja.json \
--add-host=host.docker.internal:host-gateway kajatools/kaja:latest
Then open http://localhost:41520.
On macOS, apps are configured through the UI. The configuration is stored at ~/Library/Application Support/kaja/kaja.json.
With Docker, create a kaja.json file and mount it into the container. Every entry in apps is one app: a name plus one block whose key is the app's type, holding that type's parameters:
{
"apps": [
{
"name": "users",
"twirp": {
"url": "http://host.docker.internal:41522",
"proto_dir": "users/proto"
}
},
{
"name": "teams",
"grpc": {
"url": "host.docker.internal:41523",
"reflection": true,
"headers": { "Authorization": "Bearer xxx" }
}
}
]
}Each app has a name and exactly one typed block:
| Type | Parameters |
|---|---|
grpc |
url, proto_dir (path to .proto files), reflection (use gRPC server reflection instead of local proto files), headers |
twirp |
url, proto_dir, headers |
headers are sent with each request (e.g. {"Authorization": "Bearer xxx"}); for gRPC they are sent as metadata.
Earlier versions used a top-level projects list with a protocol field. Kaja migrates these automatically on load — but to update a file by hand, move each project into apps and replace its protocol/url/protoDir/useReflection fields with a block named after the type.
Before:
{
"projects": [
{ "name": "users", "protocol": "RPC_PROTOCOL_TWIRP", "url": "http://host.docker.internal:41522", "protoDir": "users/proto" }
]
}After:
{
"apps": [
{ "name": "users", "twirp": { "url": "http://host.docker.internal:41522", "proto_dir": "users/proto" } }
]
}| Argument | Description |
|---|---|
--pull always |
Always pull the latest image. Kaja is updated frequently. |
--name kaja |
Name the container for easy management. |
-d |
Run in detached mode. |
-p 41520:41520 |
Map the container port. Kaja listens on 41520 by default. |
-v .../proto:/workspace/proto |
Mount your proto_path into the container. |
-v .../kaja.json:/workspace/kaja.json |
Mount your configuration file. |
--add-host=host.docker.internal:host-gateway |
Access host services from the container. |
The development scripts require Go and Bun installed. If not installed, they will offer to install them for you via Homebrew.
- Run in local server:
scripts/server - Run in Docker:
scripts/docker - Run the desktop app:
scripts/desktop - Test UI:
(cd ui && bun test) - TSC UI:
(cd ui && bun run tsc) - Test server:
(cd server && go test ./... -v) - Update demo protos:
scripts/demo-protos(The demo services are deployed via kaja/tools/website)