@everme/qwencode
v0.7.10
Published
Native EverMe memory hooks for Qwen Code.
Readme
@everme/qwencode
Native EverMe memory hooks for Qwen Code.
What it does
Qwen Code runs hooks that follow the Claude Code hook contract: stdin carries
the hook input as JSON, stdout is parsed as hook output, and exit code 2
blocks the operation. evercli plugin install qwencode registers three
events:
| Event | Mode | What it does |
|---|---|---|
| SessionStart | sync | Injects the durable Profile block once per session. |
| UserPromptSubmit | sync | Injects recall for a submitted prompt as additionalContext. |
| Stop | sync, detaches | Starts a detached worker that uploads the finished turn, then exits. |
The install also does these steps:
- It stages this bundle at
<qwen-home>/everme/. - It writes credentials to
<qwen-home>/everme.envwith mode0600. - It adds the three hooks and the read-only
everme-memoryMCP server to<qwen-home>/settings.json. Other keys, the user's own hooks and other MCP servers stay unchanged. The file then holds a live token, so its mode becomes0600.
<qwen-home> is $QWEN_HOME, or ~/.qwen. Each hook command passes it as
an argument after the event name, because a hook process does not inherit a
variable that names it.
Start a new Qwen Code session after install so that it loads the hooks.
Why recall needs submitted_prompt
UserPromptSubmit also fires on tool-result and hook continuations. On those
calls prompt is not what the user typed. Qwen Code sets submitted_prompt
only on a real submission, and its documentation says to treat a missing
submitted_prompt as "no user text". So recall runs only when
submitted_prompt is present.
Why Stop detaches
SessionEndfires only when the CLI exits, soStopis the capture boundary.- Qwen Code supports
"async": trueon a hook, but it kills async hooks when the CLI exits. In-pmode the CLI exits right after the turn, so an async upload can die before it finishes. - So
Stopis registered as a synchronous hook that only starts a detached worker (bin/worker.js) and exits. The turn waits for one node start, and the worker outlives the CLI. Two workers of one session cannot post the same delta twice, because the SDK checkpoint serializes read, upload and commit per session.
How a turn is read
Every hook payload carries transcript_path, which points to
<qwen-home>/projects/<sanitized-cwd>/chats/<session-id>.jsonl. Qwen Code
forked Gemini CLI, so the records are Gemini-shaped:
| Record | Uploaded as |
|---|---|
| user with provenance: "real_user" (no subtype, mid_turn_user_message or realtime_message) | user, text parts only |
| assistant text parts | assistant content |
| assistant functionCall {id, name, args} | toolCalls with a JSON-string arguments |
| tool_result functionResponse {id, response} | tool, linked by id; content is output or error |
These are not uploaded:
- Reasoning parts (
thought: true). - The
<qwen:user-prompt-submit-context>part that holds injected hook context, and a leading<everme_recall>/<everme_profile>block. - Cron, notification and Goal runtime user records, which the host wrote.
systemrecords and internalcode_mode_tool_resultresults.
The file is a tree. The reader takes the last conversation record as the leaf
and walks parentUuid back to the root, the same way Qwen Code rebuilds a
session. A rewound turn is therefore never uploaded. Fragments that share a
uuid are merged in file order. Subagent runs are written to separate files,
so the parent transcript never holds them.
The file has no end-of-turn marker. The last assistant text of each user turn
that makes no further tool call is marked turnComplete.
The upload is a delta against a per-session checkpoint keyed by native record
ids, with deduplication: "client-native-id". The first Stop after install
uploads only the latest turn.
Configuration
The hook reads its credentials from <qwen-home>/everme.env, which evercli
writes. You can override the location in these ways:
EVERME_ENV_FILE_PATHsets the path of the credential file.EVERCLI_QWENCODE_CONFIG_DIRsets the Qwen home when no argument names it.
Without credentials the hooks are silent: no output, no error, exit code 0. Memory must never block a turn, so every failure path exits with code 0 and writes one line to stderr.
Uninstall
evercli plugin uninstall qwencodeTo uninstall manually, do these steps:
- In
<qwen-home>/settings.json, remove theeverme-named handlers fromhooksand themcpServers["everme-memory"]entry. Keep every other hook and server. Remove an event key only if it becomes empty. - Run
rm -rf <qwen-home>/everme <qwen-home>/everme.env.
Tests
npm test --workspace @everme/qwencodeThe transcript fixture is reconstructed from the Qwen Code 0.26.1 recorder source, not captured from a live session.
License
Apache-2.0
