# Introspection — the container `ibmi`, and which system it hits

> Custom SQL tools must be built against the **real** schema — Db2 for i column/table names differ per system and version, so never guess. Introspect with `$AB ibmi` (`scripts/container_ibmi.py`), which execs the `ibmi` binary **inside** the stack's `api-<id>` container. A **toolset-only** agent needs none of this.

## Why the container `ibmi`, not the host one

`uv run "$AB" ibmi --instance <id> -- <args>` runs `<compose> -f ~/.ixora/docker-compose.yml exec -T api-<id> ibmi <args>`. The `api-<id>` container connects through its `IBMI_*` env — the creds the ixora stack is **deployed** with — so the schema you introspect is the one the agent queries at run time.

The **host** `ibmi` has its own `~/.ibmi` registry, independent of Ixora, that may point at a different box. SQL that passes the host `ibmi validate` can then fail at run time against the real system. So: introspect through the container; if you ever do use the host `ibmi`, first confirm it targets the same IBM i host the Ixora instance uses.

**Stack instances only.** The container exists only for stack instances. An external / `--url` instance has no local container, and a workspace instance runs its **own** compose stack (no `api-<id>` service in `~/.ixora/docker-compose.yml`) — for those, introspect via that AgentOS's own agents, or build a toolset-only agent. `$AB resolve --instance <id>` shows `kind` and `ibmi_via`; a stack instance prints the `ibmi …` invocation, every other kind prints `null` (and `$AB ibmi` rejects it with a clear error).

## The introspection surface

`$AB ibmi` passes everything after `--` to the container `ibmi` verbatim, so its full CLI is available (see the `ibmi` skill). The common ones while designing tools:

```bash
uv run "$AB" ibmi --instance <id> -- --help                 # the container ibmi's surface — check before guessing
uv run "$AB" ibmi --instance <id> -- tables <SCHEMA>        # start here when the user named the schema
uv run "$AB" ibmi --instance <id> -- columns <SCHEMA> <TABLE>
uv run "$AB" ibmi --instance <id> -- describe <SCHEMA>.<OBJECT>
uv run "$AB" ibmi --instance <id> -- schemas                # only to discover an unknown schema (row-capped)
uv run "$AB" ibmi --instance <id> -- validate "<candidate SQL>"
uv run "$AB" ibmi --instance <id> -- sql "<SELECT …>"       # ad-hoc query (it's `sql`, not `query`)
```

**Flag ordering:** target flags (`--instance` / `--url` / `--user-tools-dir` / `--ixora-dir` / `--compose-cmd`) go **before** the `--`; everything after `--` is forwarded to the container `ibmi`. Append `--raw` there for JSON, e.g. `… -- tables <SCHEMA> --raw` (that's the container ibmi's JSON flag, distinct from `ixora`'s `--json`). A target flag placed *after* `--` is caught and rejected rather than silently mis-targeting.

## Which `<id>`

`<id>` is a configured instance id from `~/.ixora/ixora-systems.yaml` — the same id the `ixora` CLI uses. Discover the valid ids (and each instance's kind) with `ixora instances list` or `ixora stack list`; omit `--instance` when only one instance is configured. `$AB resolve --instance <id>` confirms a selection (instance id, kind, endpoint, `ibmi_via`) before you introspect.

## Where the agent's tools live

`ixora agents create` writes a custom-tool agent's tools into the managed stack at `~/.ixora/user_tools/<agent-id>/` (bind-mounted to `/data/user_tools`, read at run time — no restart). Your `.agent.yaml` (and any `--ibmi-tools` file) in the repo stay the **source of truth**; the stack holds a copy. `ixora agents delete <agent-id>` removes the server-side copy.

## Validation layers (the verify run is the only real proof)

1. `$AB ibmi -- validate "<statement>"` — syntax + referenced-object existence, **no execution**.
2. `ixora agents create --dry-run` — the resolved spec; `create` then schema-checks each tool server-side (missing `source`/`description`, unknown fields, wrong types).
3. **The verify run** (`ixora agents run`, then the run's trace via `ixora traces list --run-id` → `ixora traces get <trace_id> --json`) — the only thing that binds parameters and executes, so parameter-marker / type errors (Db2 `SQL0418`) surface only here. Never call an agent "done" before a clean verify run.

## See also
- [`tool-yaml.md`](tool-yaml.md) · [`manifest.md`](manifest.md) · `ibmi` skill (the container CLI's full surface) · `use-ixora` skill → `references/systems.md`
