Skip to content
CLI
Knowledge Bases

Knowledge Bases

The hutly kbs command group manages knowledge bases (KBs) — the searchable document stores Hutly agents query for grounded answers. It covers KB identity (title, description, type), the files inside a KB (upload, list, download, delete, reindex), semantic search, triggers (rules that run an agent or workflow against newly-ingested files), and a YAML round-trip for version control.

All commands operate against the org and credentials resolved from your environment (HUTLY_ORG_ID, HUTLY_API_KEY) or .hutlyrc.yaml — see Configuration. Most read commands emit JSON by default; pass --pretty to indent it. The --json flag is accepted everywhere as a no-op for compatibility.

Identity

list

List the knowledge bases for the current org.

hutly kbs list
hutly kbs list --query lease --limit 25
hutly kbs list --include-personal --pretty
Option Description
-q, --query <q> Filter KBs by title/description
-l, --limit <n> Max results (default 100)
-c, --cursor <n> Pagination cursor
--include-personal Also include personal KBs created by the caller
--pretty Pretty-print JSON output

get

Fetch a KB together with the first page of its files and its triggers — the full detail view.

hutly kbs get <kbId>
hutly kbs get <kbId> --pretty

describe

Show only a KB’s metadata. Unlike get, it omits the customInstructions body and does not include files or triggers — use it for a quick identity check.

hutly kbs describe <kbId> --pretty

create

Create a new knowledge base. Both --title and --description are required; the description is LLM-facing — it tells agents when to search this KB.

hutly kbs create \
  --title "Tenancy Legislation" \
  --description "Search for Australian residential tenancy acts and regulations." \
  --type ORGANIZATION
Option Description
--title <title> KB title (required)
--description <description> LLM-facing description (required)
--type <type> ORGANIZATION or PERSONAL (default ORGANIZATION)

update

Update a KB’s title and/or description. The API only accepts those two fields. Pass at least one flag — whichever you omit is preserved from the current value.

hutly kbs update <kbId> --title "Tenancy Legislation (VIC)"
hutly kbs update <kbId> --description "Victorian residential tenancy law only."

delete

Permanently delete a KB and all its files, pages, and embeddings. Irreversible — prompts for confirmation unless -y is passed.

hutly kbs delete <kbId>
hutly kbs delete <kbId> --yes

Search

search

Semantic (embedding-based) search across knowledge bases. With no --kbId, it searches every accessible KB — your own org’s plus any public KBs anywhere. Pass --kbId (repeatable) to scope to specific KBs.

# Search everything accessible
hutly kbs search "notice period for rent increase"

# Scope to two KBs, raise the result count
hutly kbs search "bond claims" --kbId kb_abc --kbId kb_def --limit 10

# Assert the owning org of a public/legislation KB
hutly kbs search "smoke alarms" --kbId kb_pub --orgId org_legis
Option Description
--kbId <id> Scope to this KB id; repeat to search a list
--orgId <id> Assert the owning org for each --kbId (repeatable, parallel to --kbId)
-l, --limit <n> Max results (default 5)
--offset <n> Skip the first N results (advanced; raise --limit for more rows)
--file-pattern <pattern> Only search inside files matching this pattern
--pretty Pretty-print JSON output

When --orgId is supplied, the number of --orgId values must match the number of --kbId values, or the command errors. Semantic search has no page count — to get more matches, raise --limit rather than paging with --offset.

Files

The hutly kbs files group manages the documents inside a KB.

files upload

Upload a local file to a KB. The bytes go directly to S3 via a presigned URL — never through Lambda. By default the command is fire-and-forget (S3 triggers async ingestion); pass --wait to poll until ingestion reaches READY or ERROR.

# Fire-and-forget
hutly kbs files upload <kbId> ./docs/lease.pdf

# Block until ingestion finishes
hutly kbs files upload <kbId> ./docs/lease.pdf --wait --timeout 600

# Override the inferred content type
hutly kbs files upload <kbId> ./data.bin --content-type application/pdf
Option Description
--wait Poll until ingestion finishes (READY or ERROR)
--timeout <seconds> Wait timeout in seconds (default 300)
--content-type <type> Override the inferred content type

With --wait, the command exits non-zero on ingestion ERROR or on timeout.

files list

List files in a KB, optionally filtered by name or ingestion status.

hutly kbs files list <kbId>
hutly kbs files list <kbId> --status PROCESSING
hutly kbs files list <kbId> --query lease --limit 50
Option Description
-q, --query <q> Filter by file name
-s, --status <status> Filter by status: WAITING-UPLOAD, ENQUEUED, PROCESSING, READY, ERROR
-l, --limit <n> Max results (default 100)
-c, --cursor <n> Pagination cursor
--pretty Pretty-print JSON output

files download

Get a short-lived download link for a KB file. Prints the URL by default, or saves the file body to disk with -o.

# Print a presigned URL
hutly kbs files download <kbId> <fileId>

# Save to disk
hutly kbs files download <kbId> <fileId> -o ./lease.pdf
Option Description
-o, --output <file> Save the file body to this local path instead of printing the URL

files delete

Delete a file from a KB, removing its pages and embeddings. Prompts for confirmation unless -y is passed.

hutly kbs files delete <kbId> <fileId>
hutly kbs files delete <kbId> <fileId> --yes

files reindex

Re-trigger ingestion for a file — re-chunk and re-embed it. Runs asynchronously via SQS. Pass --triggers-only to re-run the KB’s triggers against the file’s existing embeddings without re-chunking or re-embedding.

hutly kbs files reindex <kbId> <fileId>
hutly kbs files reindex <kbId> <fileId> --triggers-only
Option Description
--triggers-only Only re-run KB triggers against existing embeddings (skip re-chunk + re-embed)

Triggers

The hutly kbs triggers group manages triggers — rules that run an agent or workflow against newly-ingested KB files. Write operations (create, update, delete) are admin-only. The legacy action-chain trigger type is deprecated and cannot be created or updated from the CLI; existing ones still surface in list/get for visibility.

triggers list

List the triggers configured on a KB.

hutly kbs triggers list <kbId> --pretty
Option Description
-l, --limit <n> Max results (default 100)
-c, --cursor <n> Pagination cursor
--pretty Pretty-print JSON output

triggers get

Fetch a single trigger.

hutly kbs triggers get <kbId> <triggerId> --pretty

triggers create

Create a trigger (admin-only). --type is required. For agent triggers, --agent-id and --prompt are required; for workflow triggers, --workflow-id is required. Conditions are a JSON array of { field, comparison, value } objects, passed inline or from a file.

# Agent trigger that fires on PDF files
hutly kbs triggers create <kbId> \
  --type agent \
  --agent-id agt_123 \
  --prompt "Summarise this lease and extract key dates." \
  --conditions '[{"field":"fileName","comparison":"ENDS_WITH","value":".pdf"}]'

# Workflow trigger, conditions from a file
hutly kbs triggers create <kbId> \
  --type workflow \
  --workflow-id wf_456 \
  --conditions-file ./conditions.json
Option Description
--type <type> agent or workflow (required)
--agent-id <id> Agent to run (required for type=agent)
--workflow-id <id> Workflow to run (required for type=workflow)
--prompt <text> Prompt passed to the agent (required for type=agent)
--conditions <json> Inline JSON array of condition objects
--conditions-file <path> Read the conditions JSON array from a file

Pass either --conditions or --conditions-file, not both.

triggers update

Update a trigger (admin-only). The API replaces the trigger fully — pass every field you want kept, with the same required-field rules as create.

hutly kbs triggers update <kbId> <triggerId> \
  --type agent \
  --agent-id agt_123 \
  --prompt "Updated prompt." \
  --conditions '[{"field":"fileName","comparison":"CONTAINS","value":"lease"}]'

triggers delete

Delete a trigger (admin-only). Prompts for confirmation unless -y is passed.

hutly kbs triggers delete <kbId> <triggerId> --yes

YAML round-trip

KBs support a pull/push round-trip so a KB’s identity and triggers can be tracked in version control. push applies only the KB identity (title, description, and type on create) — triggers in the YAML are advisory and are not applied; manage them with hutly kbs triggers. Files are never part of the round-trip — manage them with hutly kbs files.

pull

Fetch a KB and write its identity + triggers to a YAML file. Files are not included.

hutly kbs pull <kbId>
hutly kbs pull <kbId> -o ./kbs/tenancy.yaml
Option Description
-o, --output <file> Output path (defaults to ./kb-<kbId>.yaml)

The generated YAML looks like:

knowledgeBaseId: !org_map
  your-org-id: kb_abc123
title: Tenancy Legislation
llmDescription: Search for Australian residential tenancy acts and regulations.
type: ORGANIZATION
isPublic: false
triggers:
  - type: agent
    agentId: agt_123
    agentName: Lease Summariser
    prompt: Summarise this lease and extract key dates.
    conditions:
      - field: fileName
        comparison: ENDS_WITH
        value: .pdf

The knowledgeBaseId is emitted as an !org_map so the same file can resolve to different KB ids per org. The triggers block is informational on push.

push

Create or update a KB from a YAML file. Idempotent on knowledgeBaseId: if the YAML carries one (and --force-new is not set), the KB is updated in place; otherwise a new KB is created and its id is written back into the YAML file. When the YAML contains triggers, push warns that it does not apply them.

# Create or update from YAML
hutly kbs push ./kbs/tenancy.yaml

# Always create a new KB, ignoring any knowledgeBaseId in the file
hutly kbs push ./kbs/tenancy.yaml --force-new

# Substitute a variable used in the YAML
hutly kbs push ./kbs/tenancy.yaml --var env=prod
Option Description
--force-new Always create a new KB (ignore existing knowledgeBaseId in YAML)
-v, --var <key=value> Set a variable value (repeatable)

After a create, commit the updated YAML so the written-back knowledgeBaseId is preserved for future idempotent pushes.

All commands exit 0 on success and non-zero on failure, printing the error to stderr.