Three defects surfaced during end-to-end RAG verification — the first two
block real chat usage, the third makes Linux CI flaky:
1. KB id detection — `IsKBID` was checking
`strings.HasPrefix(s, "kb_")`, but WeKnora generates KB ids as bare
UUIDs (internal/types/knowledge_base.go: `uuid.New().String()` stored
in a `varchar(36)` column). Real ids therefore fell through to the
name-resolution path:
$ weknora chat ... --kb a32a63ff-fb36-4874-bcaa-30f48570a694
Error: knowledge base not found: a32a63ff-...
Switched the discriminator to a UUID regex
(`^[0-9a-fA-F]{8}-…-[0-9a-fA-F]{12}$`). KB names are arbitrary
user-supplied strings, so the canonical 8-4-4-4-12 form is an
unambiguous signal. Mirrors gcloud `--project`'s id-vs-name detection.
2. SSE terminal-frame — the accumulator's `Append` was gating
finalization on `r.Done`, but the server's KnowledgeQAStream protocol
emits a leading `agent_query` frame with `done=true` to deliver
session + message metadata *before* the answer fragments arrive:
event: message
data: {"response_type":"agent_query","content":"","done":true,…}
event: message
data: {"response_type":"answer","content":"你好","done":false}
…
event: message
data: {"response_type":"complete","content":"","done":true}
The accumulator therefore flipped to `finished=true` on frame #1 and
discarded every subsequent answer fragment — `weknora chat … --json`
returned `answer: ""` even though the LLM reported completion_tokens
> 0. Fixed: terminate only on `response_type == complete`.
References still captured opportunistically (they may arrive on a
dedicated `references` event before the terminator).
3. doctor credential_storage CI isolation — the check probes the real
OS keyring via `secrets.NewBestEffortStore()`: present on macOS dev
machines → StatusOK; absent on Linux CI runners without libsecret /
Gnome-Keyring → StatusWarn ("falling back to file store"). That
host-dependence was leaking into two test classes that assumed
StatusOK:
* cmd/doctor/doctor_test.go: TestDoctor_AllOK and
TestDoctor_NoConfig_StillRunsCredentialStorage already had a
withCredStoreFactory seam but didn't use it. Added the pin.
* acceptance/contract/envelope_test.go: doctor.success_offline
and doctor.error_network golden cases. The contract test runs
through the cobra tree in-process and shares cmd/doctor's
package-level credStoreFactory var — but couldn't reach it
because the existing seam was unexported.
Fix: export `doctor.SetCredStoreFactoryForTest(fn) (restore func())`
for out-of-package tests; acceptance/contract/helpers_test.go adds
a TestMain that pins the factory to a MemStore-returning closure
for the whole suite (MemStore is neither *FileStore nor a real
keyring, so doctor's type-switch hits StatusOK). Production stays
at secrets.NewBestEffortStore — only the test hook is now reachable
from across packages.
Test fixtures and goldens that used the old `kb_xxx` literals or
`Done: true` terminators were rewritten to use real UUIDs and
`ResponseType: ResponseTypeComplete` respectively. Per-command --help
text and Long descriptions / Examples now show a UUID rather than
`kb_…` so users see the correct shape from the start. New
TestAccumulator_IgnoresAgentQueryDone pins the SSE terminator bug so
it can't regress.
Tests: 24 cli packages green on macOS dev + Linux/macOS/Windows CI
matrix. Verified end-to-end against a live WeKnora server: `weknora
chat "..." --kb <UUID> --no-stream --json` returns the full LLM answer
in the envelope, live token streaming in TTY mode works, and the
credential_storage check renders deterministic envelopes across hosts.
5.1 KiB
weknora — WeKnora CLI
A command-line interface for the WeKnora RAG knowledge-base server. Lets you authenticate, manage knowledge bases and documents, run hybrid search, and ask streaming RAG questions from your terminal or from an AI agent.
$ weknora --help
WeKnora CLI lets you authenticate, browse knowledge bases, and run
hybrid searches against a WeKnora server from your shell or an AI agent.
Available Commands:
api Make a raw API request to the WeKnora server
auth Manage authentication credentials and contexts
chat Ask a streaming RAG question against a knowledge base
context Manage CLI contexts (named connection targets)
doc Manage documents in a knowledge base
doctor Run 4 self-checks: base URL, auth, server version, credential storage
kb Manage knowledge bases
link Bind the current directory to a knowledge base
search Hybrid (vector + keyword) chunk retrieval against a knowledge base
version Show CLI build metadata
The command surface mirrors gh CLI's <noun> <verb> convention. See
AGENTS.md for the operational contract that AI agents
(Claude Code, Cursor, Aider, …) can rely on: envelope schema, exit-code
protocol, error-code registry, and per-command guidance.
Install
From source
Requires Go 1.24+.
git clone https://github.com/Tencent/WeKnora.git
cd WeKnora/cli
go build -o weknora .
sudo mv weknora /usr/local/bin/ # or anywhere on $PATH
Pre-built binaries
Pre-built binaries for Linux / macOS / Windows are produced by CI on each release. Grab the latest from the Releases page once v0.2 ships.
5-minute quickstart
# 1. Log in to your WeKnora server (interactive password prompt)
weknora auth login --host https://kb.example.com
# 2. Or pipe an API key from stdin (for CI / agents)
echo "sk-..." | weknora auth login --host https://kb.example.com --with-token
# 3. List knowledge bases
weknora kb list
# 4. Bind this directory to a knowledge base — subsequent commands auto-resolve --kb
weknora link --kb my-knowledge-base
# 5. Upload a document
weknora doc upload notes.md
# 6. Search
weknora search "what is reciprocal rank fusion?"
# 7. Ask the LLM (streams to terminal)
weknora chat "summarise the design doc"
Multi-context
Switch between several WeKnora servers (or several tenants on the same server) without re-logging in:
weknora auth login --host https://prod.example.com --name prod
weknora auth login --host https://staging.example.com --name staging --with-token < .staging-key
weknora auth list
weknora context use prod
Credentials are persisted to your OS keyring (Keychain on macOS, libsecret on
Linux, Wincred on Windows) when available, otherwise to a 0600-mode file
under $XDG_CONFIG_HOME/weknora/secrets/. The active context lives in
~/.config/weknora/config.yaml.
To remove a context's stored credentials:
weknora auth logout # current context
weknora auth logout --name staging # specific
weknora auth logout --all
JSON envelope output
Every command supports --json, returning a stable envelope shape:
{
"ok": true,
"data": { /* command-specific payload */ },
"_meta": { "context": "prod", "kb_id": "a32a63ff-fb36-4874-bcaa-30f48570a694" }
}
On error:
{
"ok": false,
"error": {
"code": "auth.unauthenticated",
"message": "...",
"hint": "run `weknora auth login`"
}
}
The full schema, error-code registry, and exit-code protocol (0 / 1 / 2 / 10 / 130) are documented in AGENTS.md.
Agent / scripting integration
Designed to be agent-first:
--dry-runpreviews any write command (kb create/delete, doc upload/delete, api POST/PUT/PATCH/DELETE) without hitting the server, emitting an envelope withriskclassification anddry_run: true.-y/--yesskips confirmation prompts for high-risk writes. Without-yon a non-TTY/--jsoninvocation, destructive commands returnerror.code: input.confirmation_requiredand exit code 10 so an agent can ask the user before retrying.--jsoncoexists with the global--context <name>for single-shot context override.- Set
CLAUDECODEorCURSOR_AGENTenvironment variables to surface per-command "AI agents:" guidance in--helpoutput.
Health check
Run weknora doctor for a 4-status diagnostic (OK / warn / fail /
skip) covering base URL reachability, authentication, server-CLI
version skew, and credential storage backend. Add --json for
machine-readable output, --offline to skip network checks.
Development
# Run unit + contract tests
go test ./...
# Run the real-server e2e suite (requires WEKNORA_E2E_HOST + token env vars)
go test -tags acceptance_e2e ./acceptance/e2e/...
# Static analysis
go vet ./...
CI (.github/workflows/cli.yml) runs build + unit + contract tests on Linux /
macOS / Windows × Go 1.24, path-filtered to changes under cli/.
License
MIT — see the repository LICENSE.