Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,32 @@ You can communicate back and forth by mentioning your teammate in your response
<!-- TEAMMATES_START -->
<!-- TEAMMATES_END -->

## Workspace Tools

OpenViking CLI tools are available in each agent workspace:

- Path: `.tinyclaw/tools/openviking/`
- Main command: `./ovk.sh`
- Shortcuts: `./ovk-ls.sh`, `./ovk-read.sh`, `./ovk-write.sh`

Environment variables:

- `OPENVIKING_BASE_URL` (default `http://127.0.0.1:8320`)
- `OPENVIKING_API_KEY` (optional)
- `OPENVIKING_PROJECT` (optional)

Auto-sync behavior:

- `on_turn`: each completed turn is appended and synced to `viking://resources/tinyclaw/sessions/<agent_id>/active.md`
- `on_session_end`: when a reset is consumed, prior session is archived to `viking://resources/tinyclaw/sessions/<agent_id>/closed/<timestamp>.md`
- set `TINYCLAW_OPENVIKING_AUTOSYNC=0` to disable

Pre-prompt retrieval:

- before each external user turn, TinyClaw attempts to read `viking://resources/tinyclaw/sessions/<agent_id>/active.md`
- selected relevant turns are injected as `[OpenViking Retrieved Context]`
- set `TINYCLAW_OPENVIKING_PREFETCH=0` to disable

## Soul

You have a soul file at `.tinyclaw/SOUL.md`. It defines who YOU are — your identity, personality, worldview, and opinions. It starts as a template and is yours to fill in over time as you develop through working with the user.
Expand Down
75 changes: 75 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,12 @@ Commands work with `tinyclaw` (if CLI installed) or `./tinyclaw.sh` (direct scri
| `team remove <id>` | Remove a team | `tinyclaw team remove dev` |
| `team visualize [id]` | Live TUI dashboard for team chains | `tinyclaw team visualize dev` |

### Tool Commands

| Command | Description | Example |
| ------------------------ | ------------------------------------------------ | -------------------------- |
| `tools sync [agent_id]` | Sync OpenViking CLI tools into agent workspace(s) | `tinyclaw tools sync coder` |

### Configuration Commands

| Command | Description | Example |
Expand Down Expand Up @@ -237,6 +243,75 @@ export TINYCLAW_SKIP_UPDATE_CHECK=1
| `send <message>` | Send message to AI manually | `tinyclaw send "Hello!"` |
| `send <message>` | Route to specific agent | `tinyclaw send "@coder fix bug"` |

## 🧰 OpenViking Workspace Tools

TinyClaw can provision lightweight OpenViking tools into each agent workspace:

```bash
tinyclaw tools sync
```

Tools are installed at:

```bash
<workspace>/<agent_id>/.tinyclaw/tools/openviking/
```

Common usage from an agent directory:

```bash
cd .tinyclaw/tools/openviking
./ovk-ls.sh /
./ovk-read.sh /context/spec.md
./ovk-write.sh /context/spec.md "updated content"
./ovk.sh res-get viking://workspace/resource
```

Environment variables:

- `OPENVIKING_BASE_URL` (default: `http://127.0.0.1:8320`)
- `OPENVIKING_API_KEY` (optional)
- `OPENVIKING_PROJECT` (optional)

### OpenViking Native Session Write Path

TinyClaw supports OpenViking native session lifecycle as the primary write path:

- `POST /api/v1/sessions` to create/reuse session IDs per `(channel, senderId, agentId)` mapping
- `POST /api/v1/sessions/{id}/messages` for `user` and `assistant` turns
- `POST /api/v1/sessions/{id}/commit` when reset/session-end is consumed

Setup integration:

- `tinyclaw setup` now prompts whether to enable OpenViking memory
- if enabled, setup can install OpenViking CLI and generate `~/.openviking/ov.conf` (includes LLM API key for OpenViking internals)
- `tinyclaw start` auto-starts OpenViking server (when enabled + auto_start) and exports OpenViking env vars for channel/queue processes

Feature flags:

- `TINYCLAW_OPENVIKING_SESSION_NATIVE=1` enable native session write path
- `TINYCLAW_OPENVIKING_AUTOSYNC=0` disable legacy markdown sync fallback (`active.md`/`closed/*.md`)

Legacy markdown sync remains as a compatibility fallback.

### Pre-Prompt Retrieval (OpenViking)

Before invoking the model for an external user turn, TinyClaw can prefetch related context via:

- `POST /api/v1/search/search` (native, typed `memories/resources/skills`, optionally scoped with `session_id`)
- legacy fallback (`find-uris` + `read` on `active.md` and archived sessions) when native search is disabled or misses

Environment flags:

- `TINYCLAW_OPENVIKING_PREFETCH=0` disable pre-prompt retrieval
- `TINYCLAW_OPENVIKING_SEARCH_NATIVE=1` enable native search as primary prefetch path
- `TINYCLAW_OPENVIKING_PREFETCH_TIMEOUT_MS` prefetch/search timeout (default: `5000`)
- `TINYCLAW_OPENVIKING_COMMIT_TIMEOUT_MS` native session commit timeout (default: `15000`)
- `TINYCLAW_OPENVIKING_PREFETCH_MAX_CHARS` max injected chars (default: `2800`)
- `TINYCLAW_OPENVIKING_PREFETCH_MAX_TURNS` max selected turns (default: `4`)
- `TINYCLAW_OPENVIKING_PREFETCH_MAX_HITS` max typed native hits injected (default: `8`)
- `TINYCLAW_OPENVIKING_SEARCH_SCORE_THRESHOLD` optional native score threshold passed to OpenViking search API

### In-Chat Commands

These commands work in Discord, Telegram, and WhatsApp:
Expand Down
81 changes: 81 additions & 0 deletions lib/agents.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,84 @@
# AGENTS_DIR set after loading settings (uses workspace path)
AGENTS_DIR=""

copy_openviking_tools_to_agent_dir() {
local agent_dir="$1"
local tools_src="$SCRIPT_DIR/lib/templates/agent-tools/openviking"
local tools_dest="$agent_dir/.tinyclaw/tools/openviking"

[ -d "$tools_src" ] || return 0

mkdir -p "$tools_dest"
cp "$tools_src"/* "$tools_dest/" 2>/dev/null || true

if [ -f "$SCRIPT_DIR/dist/tools/openviking-tool.js" ]; then
cp "$SCRIPT_DIR/dist/tools/openviking-tool.js" "$tools_dest/openviking-tool.js"
fi

if [ -f "$SCRIPT_DIR/src/tools/openviking-tool.ts" ]; then
cp "$SCRIPT_DIR/src/tools/openviking-tool.ts" "$tools_dest/openviking-tool.ts"
fi

chmod +x "$tools_dest/ovk.sh" "$tools_dest/ovk-ls.sh" "$tools_dest/ovk-read.sh" "$tools_dest/ovk-write.sh" 2>/dev/null || true
}

sync_agent_tools() {
load_settings || return 0
local agents_dir="$WORKSPACE_PATH"
[ -d "$agents_dir" ] || return 0

local target_agent="${1:-}"
if [ -n "$target_agent" ]; then
local agent_dir="$agents_dir/$target_agent"
[ -d "$agent_dir" ] || return 0
copy_openviking_tools_to_agent_dir "$agent_dir"
return 0
fi

local agent_ids
agent_ids=$(jq -r '(.agents // {}) | keys[]' "$SETTINGS_FILE" 2>/dev/null) || return 0
for agent_id in $agent_ids; do
local agent_dir="$agents_dir/$agent_id"
[ -d "$agent_dir" ] || continue
copy_openviking_tools_to_agent_dir "$agent_dir"
done
}

agent_tools_sync_command() {
if [ ! -f "$SETTINGS_FILE" ]; then
echo -e "${RED}No settings file found. Run setup first.${NC}"
exit 1
fi

load_settings
AGENTS_DIR="$WORKSPACE_PATH"

local target_agent="${1:-}"
if [ -n "$target_agent" ]; then
local exists
exists=$(jq -r "(.agents // {}).\"${target_agent}\" // empty" "$SETTINGS_FILE" 2>/dev/null)
if [ -z "$exists" ]; then
echo -e "${RED}Agent '${target_agent}' not found.${NC}"
exit 1
fi
copy_openviking_tools_to_agent_dir "$AGENTS_DIR/$target_agent"
echo -e "${GREEN}✓ Synced OpenViking tools to @${target_agent}${NC}"
echo " Path: $AGENTS_DIR/$target_agent/.tinyclaw/tools/openviking"
return
fi

local count=0
local agent_ids
agent_ids=$(jq -r '(.agents // {}) | keys[]' "$SETTINGS_FILE" 2>/dev/null)
for agent_id in $agent_ids; do
copy_openviking_tools_to_agent_dir "$AGENTS_DIR/$agent_id"
count=$((count + 1))
done

echo -e "${GREEN}✓ Synced OpenViking tools to ${count} agent(s)${NC}"
echo " Tools path: <workspace>/<agent_id>/.tinyclaw/tools/openviking"
}

# Ensure all agent workspaces have .agents/skills symlinked
ensure_agent_skills_links() {
local skills_src="$SCRIPT_DIR/.agents/skills"
Expand Down Expand Up @@ -277,6 +355,9 @@ agent_add() {
echo " → Copied SOUL.md to .tinyclaw/"
fi

copy_openviking_tools_to_agent_dir "$AGENTS_DIR/$AGENT_ID"
echo " → Synced OpenViking tools to .tinyclaw/tools/openviking/"

echo ""
echo -e "${GREEN}✓ Agent '${AGENT_ID}' created!${NC}"
echo -e " Directory: $AGENTS_DIR/$AGENT_ID"
Expand Down
39 changes: 39 additions & 0 deletions lib/common.sh
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,23 @@ declare -A CHANNEL_TOKEN_ENV=(
ACTIVE_CHANNELS=()
declare -A CHANNEL_TOKENS=()
WORKSPACE_PATH=""
OPENVIKING_ENABLED="false"
OPENVIKING_AUTO_START="false"
OPENVIKING_HOST="127.0.0.1"
OPENVIKING_PORT="8320"
OPENVIKING_BASE_URL="http://127.0.0.1:8320"
OPENVIKING_CONFIG_PATH="$HOME/.openviking/ov.conf"
OPENVIKING_PROJECT=""
OPENVIKING_API_KEY=""
OPENVIKING_NATIVE_SESSION="false"
OPENVIKING_NATIVE_SEARCH="false"
OPENVIKING_PREFETCH="false"
OPENVIKING_AUTOSYNC="true"
OPENVIKING_PREFETCH_TIMEOUT_MS="5000"
OPENVIKING_COMMIT_TIMEOUT_MS="15000"
OPENVIKING_PREFETCH_MAX_CHARS="2800"
OPENVIKING_PREFETCH_MAX_TURNS="4"
OPENVIKING_PREFETCH_MAX_HITS="8"

# Logging function
log() {
Expand Down Expand Up @@ -115,6 +132,28 @@ load_settings() {
fi
done

# Load OpenViking settings
OPENVIKING_ENABLED=$(jq -r '.openviking.enabled // false' "$SETTINGS_FILE" 2>/dev/null)
OPENVIKING_AUTO_START=$(jq -r '.openviking.auto_start // false' "$SETTINGS_FILE" 2>/dev/null)
OPENVIKING_HOST=$(jq -r '.openviking.host // "127.0.0.1"' "$SETTINGS_FILE" 2>/dev/null)
OPENVIKING_PORT=$(jq -r '.openviking.port // 8320' "$SETTINGS_FILE" 2>/dev/null)
OPENVIKING_BASE_URL=$(jq -r '.openviking.base_url // "http://127.0.0.1:8320"' "$SETTINGS_FILE" 2>/dev/null)
OPENVIKING_CONFIG_PATH=$(jq -r '.openviking.config_path // empty' "$SETTINGS_FILE" 2>/dev/null)
if [ -z "$OPENVIKING_CONFIG_PATH" ]; then
OPENVIKING_CONFIG_PATH="$HOME/.openviking/ov.conf"
fi
OPENVIKING_PROJECT=$(jq -r '.openviking.project // empty' "$SETTINGS_FILE" 2>/dev/null)
OPENVIKING_API_KEY=$(jq -r '.openviking.api_key // empty' "$SETTINGS_FILE" 2>/dev/null)
OPENVIKING_NATIVE_SESSION=$(jq -r '.openviking.native_session // false' "$SETTINGS_FILE" 2>/dev/null)
OPENVIKING_NATIVE_SEARCH=$(jq -r '.openviking.native_search // false' "$SETTINGS_FILE" 2>/dev/null)
OPENVIKING_PREFETCH=$(jq -r '.openviking.prefetch // false' "$SETTINGS_FILE" 2>/dev/null)
OPENVIKING_AUTOSYNC=$(jq -r '.openviking.autosync // true' "$SETTINGS_FILE" 2>/dev/null)
OPENVIKING_PREFETCH_TIMEOUT_MS=$(jq -r '.openviking.prefetch_timeout_ms // 5000' "$SETTINGS_FILE" 2>/dev/null)
OPENVIKING_COMMIT_TIMEOUT_MS=$(jq -r '.openviking.commit_timeout_ms // 15000' "$SETTINGS_FILE" 2>/dev/null)
OPENVIKING_PREFETCH_MAX_CHARS=$(jq -r '.openviking.prefetch_max_chars // 2800' "$SETTINGS_FILE" 2>/dev/null)
OPENVIKING_PREFETCH_MAX_TURNS=$(jq -r '.openviking.prefetch_max_turns // 4' "$SETTINGS_FILE" 2>/dev/null)
OPENVIKING_PREFETCH_MAX_HITS=$(jq -r '.openviking.prefetch_max_hits // 8' "$SETTINGS_FILE" 2>/dev/null)

return 0
}

Expand Down
Loading