Minimal agent runtime with:
- gateway server
- local TUI
- configurable onboarding flow
- workspace-backed agent prompt context
- channel-based gateway routing
- explicit message/media dispatch tool
- file-backed local memory
- Node.js 20+
- npm
cd malikraw
npm install
npm run build
npm linkAfter npm link, use the CLI directly:
malikraw onboard
malikraw start
malikraw stop
malikraw restart
malikraw status
malikraw tuiRun the step-by-step setup wizard:
malikraw onboardThis writes config files under ~/.malikraw/config/, including:
system.jsonproviders.jsonagent-provider-mapping.jsonworkspace.jsonchannels.jsontools.jsonagents.jsonmemory.json
During onboarding, available skills are discovered from the repository skills/ directory. The selected skill directories are copied into the workspace under ~/.malikraw/workspace/skills/.
Current onboarding defaults:
- one agent only:
main - workspace is fixed to
~/.malikraw/workspace - model generation defaults are
temperature=0.2,contextWindow=200000,maxTokens=32000 - Feishu channel only requires
appIdandappSecret - skills / tools / channels are selected with space-toggle prompts
If you already have config saved from onboarding, the gateway runs as a background service:
malikraw start
malikraw stop
malikraw restart
malikraw statusThe gateway listens on 127.0.0.1:<gatewayPort>. Default port is 5050.
Service metadata and logs are stored under ~/.malikraw/log/service/.
Health check:
curl http://127.0.0.1:5050/healthThe gateway owns routing. Channels only implement transport-specific send/receive behavior.
- inbound:
channel -> gateway -> agent runtime - outbound:
agent runtime -> gateway -> target channel
Each conversation is keyed by:
agentId:channelId:sessionId
The built-in message tool provides explicit outbound dispatch. It returns a structured message request, and the gateway routes it to the target channel by calling that channel's sendMessage.
Example tool intent:
{
"content": "Here is the chart",
"media": [
{ "path": "artifacts/chart.png" }
]
}This is important for Feishu. File/image sending no longer relies only on parsing natural-language replies. If media is present, the Feishu channel uses the structured media pipeline.
Feishu supports:
- text replies
- markdown-style interactive cards
- image upload + send
- file upload + send
The Feishu channel now has two outbound paths:
- normal text/card output from the final assistant response
- structured
media[]dispatch from themessagetool or extracted tool results
For attachments, the channel uploads media first and then sends a message with the returned Feishu key.
The built-in web_search tool uses Brave Search API.
You can configure the Brave API key in malikraw onboard. The tool also falls back to:
export BRAVE_SEARCH_API_KEY=your_brave_api_keyThe tool calls Brave's web search endpoint and returns compact results with title, url, and description.
When the current channel is Feishu and valid Feishu app credentials are configured, the runtime also registers:
read_feishu_docupdate_feishu_doc
read_feishu_doc reads a docx URL directly, or resolves a wiki URL to its backing docx document before reading.
update_feishu_doc updates Feishu docx content from markdown text.
mode: "replace"clears the current document body and writes the new contentmode: "append"keeps the current document body and appends the new content
Current limits:
- only
docxis writable wikiis supported only when it points to adocxsheetandbitableare not supported yet
The built-in message tool lets the agent send a structured outbound message through the gateway.
Supported fields:
content- optional target overrides:
channelId,sessionId,agentId,userId,projectId media[]
Each media item supports:
path- optional
kind - optional
fileName - optional
caption
Media paths are resolved inside the workspace and validated before dispatch.
Runtime observability files are stored under:
~/.malikraw/log/runtime.log~/.malikraw/event/runtime.jsonl
Memory is local-only and always enabled.
Malikraw stores memory under MALIKRAW_HOME/state/memory as local JSON files.
It keeps:
- recent messages for a session
- current task state
memory_items- each row stores a user query and a memory content block derived from that turn
- retrieval uses the new user query to match similar past queries
- the matched
contentis injected back into the prompt as user memory
memory_tool_chain- each row stores a user query and the tool call chain used for that query
- retrieval also uses the new user query to match similar past queries
- the matched tool chains are injected into the prompt as reusable tool paths
This local store survives restarts and does not require Redis, Postgres, or any external database.
- recent local context from file-backed session state
- matched memory content from
memory_items - matched tool chains from
memory_tool_chain
Current session-history compression now has two layers:
- gateway/session-store compaction
- conservative fallback based on message count and char size
- runtime prompt compaction
- provider-driven, based on estimated token budget and model context settings
- derives compact thresholds from
contextWindowandmaxTokens - only compresses prior conversation history
- does not compress the system prompt
When runtime compaction triggers:
- it first tries a micro-compact pass on old large tool outputs
- if that is not enough, it builds a structured session handoff block and keeps the recent tail
- if that is still not enough, it falls back to a model-generated summary using
COMPACT.md - older history is compressed into a synthetic
usermessage starting with[compacted_history] - recent history is kept
- recent history is aligned to a
userboundary - compaction guidance is read from workspace
COMPACT.mdby default - compacted information is also written into
memory_items - if the model still returns a context-length error at runtime, malikraw performs one more reactive compact pass and retries automatically
This keeps the active prompt smaller without dropping older context completely.
The current system does not yet do:
- advanced forgetting
- reranking beyond the current retrieval order
malikraw tuiThe TUI registers itself as the tui channel and keeps a local in-memory session.
Build:
npm run buildRun tests:
npm test- CI runs on GitHub Actions for pushes to
mainand pull requests - npm publish is handled by GitHub Actions on version tags like
v0.1.0 - npm publishing requires an
NPM_TOKENrepository secret with publish access
- Default workspace path is
~/.malikraw/workspace - Default workspace prompt file is
~/.malikraw/workspace/AGENT.md - Runtime memory is stored under
~/.malikraw/memory - Config files live under
~/.malikraw/config/ - Bundled skills live under
skills/ - System prompt templates live under
templates/system/