> For the complete documentation index, see [llms.txt](https://docs.kira.thiennguyen.dev/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.kira.thiennguyen.dev/extension-development/sdk-reference.md).

# The kira SDK

Every action is a Go file that your extension ships, interpreted at runtime. This page is the reference for the action contract and the `*kira.Ctx` API.

## The action contract

Each entry file must be `package action` and export exactly:

```go
func Run(k *kira.Ctx) error
```

```go
package action

import (
	"bytes"
	"encoding/json"

	"kira"
)

func Run(k *kira.Ctx) error {
	token, err := k.Secret(k.Config("secretKey")) // resolved at runtime
	if err != nil {
		return err
	}
	body, _ := json.Marshal(map[string]string{"secret_key": token})
	resp, err := k.HTTP().Post(k.Config("webhookUrl"), "application/json", bytes.NewReader(body))
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	k.Logf("HTTP %d", resp.StatusCode)
	return nil
}
```

Rules:

* **Package must be `action`**, the function must be `func Run(k *kira.Ctx) error`. A non-nil return is reported as a failed run in the console.
* **Import the SDK as `"kira"`** (`import "kira"`). It's resolved by the interpreter, not a real module. For editor autocomplete and type-checking, add the compile-only stub — see [Authoring Workflow → Editor setup](/extension-development/authoring-workflow.md#editor-setup).
* **One file can back many actions.** Point several manifest actions at the same `entry` and branch on `k.Action()`:

  ```go
  func Run(k *kira.Ctx) error {
      id, _ := k.Action()
      switch id {
      case "staging":    /* ... */
      case "production": /* ... */
      }
      return nil
  }
  ```
* Use the Go **standard library** freely (`net/http`, `encoding/json`, `time`, `os`, `os/exec`, …). `fmt.Println`/stdout/stderr are captured to the run console.

## `*kira.Ctx` methods

| Method                                             | Description                                                                 |
| -------------------------------------------------- | --------------------------------------------------------------------------- |
| `Secret(id) (string, error)`                       | Raw secret value from Secrets Manager for the run's account context.        |
| `SecretField(id, field) (string, error)`           | One string field from a JSON secret.                                        |
| `Config(key) string`                               | Top-level merged config value (objects/arrays as JSON; missing = `""`).     |
| `ConfigValue(key) (any, bool)`                     | Raw decoded value; objects `map[string]any`, arrays `[]any`.                |
| `ConfigInto(v any) error`                          | Unmarshal the full merged config into a struct/map.                         |
| `ConfigRaw() string`                               | Full merged config as JSON.                                                 |
| `Log(args...)` / `Logf(fmt, args...)`              | Write a line to the run console.                                            |
| `Alert(message) error`                             | Modal with OK; **pauses the script** until dismissed.                       |
| `Confirm(message) (bool, error)`                   | OK/Cancel → `true`/`false`. Gate destructive steps.                         |
| `Ask(InputRequest) (value string, ok bool, error)` | Collect input: text / number / select.                                      |
| `ShowHTML(HTMLReport) error`                       | Render an HTML report modal (Print → PDF, Open in browser).                 |
| `Toast(ToastOptions) string`                       | **Non-blocking** toast (info/success/warning/error/loading); returns an id. |
| `UpdateToast(id, ToastOptions)`                    | Re-render a toast by id (e.g. loading → success).                           |
| `DismissToast(id)`                                 | Remove a toast by id (also cleared when the run ends).                      |
| `Action() (id, label string)`                      | The clicked button's id and label.                                          |
| `Extension() (id, name string)`                    | The owning extension's id and name.                                         |
| `Account() (id, role, region string)`              | The resolved account context.                                               |
| `Context() context.Context`                        | Cancelled on timeout/cancel — pass it to long calls.                        |
| `HTTP() *http.Client`                              | Client whose requests abort on cancel (you may also `import "net/http"`).   |

## Secrets

```go
raw, err := k.Secret("prod/api")              // full SecretString
key, err := k.SecretField("prod/api", "key")  // one field of a JSON secret
```

Resolution uses the run's account context. Only the secret id is sent to AWS — never the secret value or row data leaves the user's machine except where your script sends it.

## User dialogs (blocking)

All of these **block the script** while open; the 60-second run timeout is **paused** while a dialog is up, so waiting on the user never times the run out.

```go
// Alert — acknowledge
k.Alert("Deploy finished.")

// Confirm — branch
if ok, _ := k.Confirm("POST to PRODUCTION?"); !ok {
    return nil // user cancelled
}

// Ask — collect a value
name, ok, _ := k.Ask(kira.InputRequest{Kind: "text", Label: "Your name?", Default: "world"})
n,    ok, _ := k.Ask(kira.InputRequest{Kind: "number", Label: "How many?"}) // returns a string
env,  ok, _ := k.Ask(kira.InputRequest{
    Kind:  "select",
    Label: "Environment",
    Options: []kira.Option{
        {Label: "Staging", Value: "staging"},
        {Label: "Production", Value: "production"}, // Ask returns the chosen Value
    },
})
if !ok { /* cancelled */ }
```

## HTML reports

Pass body markup; Kira wraps it in a styled document (with default table CSS). The modal offers **Print** (→ Save as PDF) and **Open in browser** (full size, beyond the app window):

```go
var b strings.Builder
b.WriteString("<h2>Summary</h2><table><tr><th>Service</th><th>Events</th></tr>")
for _, r := range rows {
    fmt.Fprintf(&b, "<tr><td>%s</td><td>%d</td></tr>", r.Name, r.Count)
}
b.WriteString("</table>")
k.ShowHTML(kira.HTMLReport{Title: "Summary", HTML: b.String(), Width: 720, Height: 480})
// blocks until the user closes it
```

The report runs in a **sandboxed iframe** — its scripts can't reach the app. In-app the modal is clamped to the window (it scrolls); Print/Save and truly large views happen via the real browser.

## Toasts (non-blocking)

Unlike the dialogs above, `Toast` **does not block** — it flashes a transient status message and the script keeps running. Pass a `Type` (`info` default, `success`, `warning`, `error`, `loading`), a `Position` (`bottomRight` default, plus `bottom`, `bottomLeft`, `top`, `topRight`, `topLeft`), and a `Duration` in **seconds** (`0` = stay until you update/dismiss it or the run ends). `Toast` returns an id you can use to update or dismiss it:

```go
// One-shot success toast that auto-hides after 3s.
k.Toast(kira.ToastOptions{Type: "success", Message: "Saved.", Duration: 3})

// loading → result: keep a sticky spinner up, then turn it into the outcome.
id := k.Toast(kira.ToastOptions{Type: "loading", Message: "Deploying…"}) // Duration 0 = sticky
if err := deploy(); err != nil {
    k.UpdateToast(id, kira.ToastOptions{Type: "error", Message: "Deploy failed: " + err.Error(), Duration: 6})
    return err
}
k.UpdateToast(id, kira.ToastOptions{Type: "success", Message: "Deployed.", Duration: 3})
```

Any toast still on screen when the action ends is cleared automatically, so a sticky `loading` toast never strands. Unknown `Type`/`Position` values fall back to `info`/`bottomRight`.

## Next

See [Authoring Workflow](/extension-development/authoring-workflow.md) for editor setup, cancellation, debugging, versioning, and distributing.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.kira.thiennguyen.dev/extension-development/sdk-reference.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
