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
Binary file modified .DS_Store
Binary file not shown.
95 changes: 89 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# weave

**Graph-native memory CLI for AI agents.** Chat with AI that actually remembers — across sessions, across agents.
**Testing-native memory CLI for AI agents.** Run multi-step test workflows with persistent memory across sessions and specialized QA agents.

> CLI binary name: `weave-test` (replace any older `weave` examples with `weave-test`).

```
◈ weave v0.1.0
Expand All @@ -9,14 +11,15 @@

## What is Weave?

Weave is a terminal CLI agent (like Claude Code) with a twist: **persistent, graph-structured memory**. Every conversation is remembered. Memories are connected by semantic similarity, temporal sequence, and shared entities. Your agents build knowledge over time — they never cold-start.
Weave is a terminal CLI agent (like Claude Code) focused on **software testing and quality improvement**. It combines **persistent graph memory** with **multi-agent QA roles** so each run gets smarter over time.

Built on the MemWeave memory architecture:
Built on the MemWeave memory architecture plus a test orchestration layer:
- **Multi-layer memory graph** — semantic, temporal, causal, and entity edges
- **Tiered memory** — working → short-term → long-term → archival with automatic promotion and decay
- **Multi-agent** — spawn multiple agents with different personas that share a memory fabric
- **Multi-agent** — testing personas (orchestrator, edge-case hunter, report analyst) share a memory fabric
- **Hybrid retrieval** — vector similarity + graph traversal for smarter recall
- **Local-first** — works with just hash-based embeddings + SQLite, no cloud required for memory
- **Testing pipeline** — command discovery (`lint`, `typecheck`, `test`, `integration`, `e2e`, `build`) with clear run reports

## Install

Expand All @@ -43,8 +46,11 @@ weave init
# Set your API key (or use Codex auth — see below)
weave config set apiKey sk-your-openai-key

# Start chatting (memories persist automatically)
weave chat
# Initialize testing agents
weave test init

# Run the testing pipeline on current project
weave test run

# Or use Anthropic
weave config set provider anthropic
Expand All @@ -65,6 +71,83 @@ weave chat

## Commands

### Testing (Primary)

```bash
weave test init # create test-focused agents
weave test run # discover and run tests in current dir
weave test plan # preview discovered + autonomous plan
weave test run --dir ../my-app # run against another project
weave test run --workspace release # keep separate test memory per workspace
weave test run --provider anthropic # use another model provider
weave test run --model gpt-4o-mini # choose specific model for insights
weave test run --max-auto 5 # add up to 5 autonomous expansions
weave test run --no-autonomous # run only discovered commands

weave-test automation create --name "nightly smoke" --dir . --every 1d
weave-test automation remind "in 45 minutes" --name "rerun tests" --dir .
weave-test automation list
weave-test automation run <id>
weave-test automation daemon # keep scheduler running locally
```

The testing workflow:
- discovers test commands from project scripts/runtime,
- optionally proposes additional safe commands using autonomous planning (`--max-auto > 0`),
- runs them as a multi-step pipeline,
- analyzes failures and edge-case gaps,
- persists run intelligence to memory for future sessions.

### Automations

`weave-test` now supports durable test automations:

- `automation create` for recurring schedules via `--every` or `--cron`
- `automation remind` for one-time reminders/check-backs
- `automation loop` as a Claude-style recurring shortcut
- `automation daemon` to keep due automations running locally

Examples:

```bash
weave-test automation create --name "daily regression" --dir . --every 1d
weave-test automation create --name "weekday smoke" --dir . --cron "0 9 * * 1-5"
weave-test automation remind "in 2 hours" --name "rerun failed checks" --dir .
weave-test automation loop 30m --name "poll health" --dir . --target testPlan
weave-test automation list
weave-test automation pause <id>
weave-test automation resume <id>
weave-test automation run <id>
weave-test automation daemon --poll-ms 10000
```

### GitHub App Writes

`weave-test` can now write to GitHub through a GitHub App installation identity instead of your local `git push`.

Configure the app:

```bash
weave-test github app init \
--app-id 123456 \
--private-key-path /path/to/github-app.pem \
--owner your-org \
--repo your-repo

weave-test github app status
weave-test github repo connect --owner your-org --repo your-repo --save-defaults
```

Create a branch, commit local files to GitHub, and open a PR:

```bash
weave-test github branch create --branch weavetest/demo --base main
weave-test github commit --branch weavetest/demo --message "Update test flow" --dir . src/index.ts README.md
weave-test github pr create --title "Update test flow" --head weavetest/demo --base main
```

`weave-test github push` is also available as a commit-and-update-ref alias if you prefer that wording.

### Chat

```bash
Expand Down
41 changes: 41 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: "Weave Bot"
description: "AI-powered PR reviews, issue triage, and @weave mentions — powered by memweave"
author: "jayavibhavnk"

inputs:
trigger_phrase:
description: "Phrase that triggers Weave in comments (e.g. @weave)"
required: false
default: "@weave"
model:
description: "LLM model to use (e.g. gpt-4o, claude-sonnet-4-20250514)"
required: false
provider:
description: "LLM provider (openai, anthropic)"
required: false
default: "openai"

runs:
using: "composite"
steps:
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: "20"

- name: Install memweave
shell: bash
run: npm install -g memweave@latest

- name: Run Weave Action
shell: bash
run: weave-test action run
env:
GITHUB_TOKEN: ${{ github.token }}
WEAVE_TRIGGER_PHRASE: ${{ inputs.trigger_phrase }}
WEAVE_MODEL: ${{ inputs.model }}
WEAVE_PROVIDER: ${{ inputs.provider }}

branding:
icon: "cpu"
color: "purple"
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"description": "Graph-native memory CLI for AI agents — persistent, multi-agent, cross-session context",
"type": "module",
"bin": {
"weave": "./dist/index.js"
"weave-test": "./dist/index.js"
},
"main": "./dist/index.js",
"files": [
Expand Down
40 changes: 31 additions & 9 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,43 +28,55 @@ export function getDefaultConfig(): WeaveConfig {
embeddingDim: 256,
defaultAgent: "assistant",
workspacePath: path.join(WORKSPACES_DIR, "default.db"),
githubApiBaseUrl: "https://api.github.com",
};
}

export function loadConfig(): WeaveConfig {
ensureConfigDir();
const defaults = getDefaultConfig();
let config = defaults;

if (fs.existsSync(CONFIG_FILE)) {
try {
const raw = fs.readFileSync(CONFIG_FILE, "utf-8");
const saved = JSON.parse(raw);
return { ...defaults, ...saved };
config = { ...defaults, ...saved };
} catch {
return defaults;
config = defaults;
}
}

// Check environment variables
const envKey =
process.env.OPENAI_API_KEY || process.env.ANTHROPIC_API_KEY;
if (envKey) {
defaults.apiKey = envKey;
config.apiKey = envKey;
if (process.env.ANTHROPIC_API_KEY && !process.env.OPENAI_API_KEY) {
defaults.provider = "anthropic";
defaults.model = "claude-sonnet-4-20250514";
config.provider = "anthropic";
config.model = "claude-sonnet-4-20250514";
}
}

return defaults;
if (process.env.GITHUB_APP_ID) config.githubAppId = process.env.GITHUB_APP_ID;
if (process.env.GITHUB_APP_PRIVATE_KEY)
config.githubAppPrivateKey = process.env.GITHUB_APP_PRIVATE_KEY;
if (process.env.GITHUB_APP_PRIVATE_KEY_PATH)
config.githubAppPrivateKeyPath = process.env.GITHUB_APP_PRIVATE_KEY_PATH;
if (process.env.GITHUB_OWNER) config.githubOwner = process.env.GITHUB_OWNER;
if (process.env.GITHUB_REPO) config.githubRepo = process.env.GITHUB_REPO;
if (process.env.GITHUB_API_BASE_URL)
config.githubApiBaseUrl = process.env.GITHUB_API_BASE_URL;
if (process.env.GITHUB_TOKEN)
config.githubToken = process.env.GITHUB_TOKEN;

return config;
}

export function saveConfig(config: Partial<WeaveConfig>): void {
ensureConfigDir();
const existing = loadConfig();
const merged = { ...existing, ...config };

// Don't persist workspacePath if it's the default
const toSave: Record<string, unknown> = {};
const defaults = getDefaultConfig();
for (const [key, value] of Object.entries(merged)) {
Expand Down Expand Up @@ -96,6 +108,13 @@ export function setConfigValue(key: string, value: string): void {
throw new Error(`Invalid provider: ${value}. Use one of: ${VALID_PROVIDERS.join(", ")}`);
}
update[key] = p;
} else if (key === "githubApiBaseUrl") {
try {
new URL(value);
} catch {
throw new Error("githubApiBaseUrl must be a valid URL");
}
update[key] = value.replace(/\/$/, "");
} else {
update[key] = value;
}
Expand All @@ -122,7 +141,6 @@ export function listWorkspaces(): string[] {

/**
* Try to read OpenAI API key from Codex's auth.json (e.g. after `codex login --api-key`).
* See: https://developers.openai.com/codex/auth/
*/
export function getCodexAuthApiKey(): string | undefined {
try {
Expand Down Expand Up @@ -171,3 +189,7 @@ export function getProviderBaseURL(
? "http://localhost:11434/v1"
: "http://localhost:1234/v1";
}

export function getGithubApiBaseUrl(config?: Partial<WeaveConfig>): string {
return config?.githubApiBaseUrl || process.env.GITHUB_API_BASE_URL || "https://api.github.com";
}
16 changes: 14 additions & 2 deletions src/core/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,11 +167,10 @@ export class AgentMemory {
return this.graph.consolidate();
}

buildSystemPrompt(): string {
buildSystemPrompt(opts?: { skillPrompt?: string; optimizerPrompt?: string }): string {
const p = this.persona;
const parts: string[] = [];

// Identity (Cursor-style: one clear line)
if (p.systemPrompt) {
parts.push(p.systemPrompt);
} else {
Expand All @@ -188,6 +187,18 @@ export class AgentMemory {
parts.push(weaveContext);
}

// Inject optimizer-generated adaptive prompt sections
if (opts?.optimizerPrompt) {
parts.push("");
parts.push(opts.optimizerPrompt);
}

// Inject matched skills (progressive disclosure)
if (opts?.skillPrompt) {
parts.push("");
parts.push(opts.skillPrompt);
}

parts.push("");
parts.push("## Your Persistent Memory");

Expand All @@ -203,6 +214,7 @@ export class AgentMemory {
"- You have persistent memory. Important information is automatically saved between sessions. Reference recalled context when relevant; don't repeat stored facts—build on them.\n" +
"- **Tools**: Use tools when the user asks you to examine, edit, or run something. Prefer `read_file` before `edit_file` or `write_file`. For large files use `start_line`/`end_line`. Paths are relative to the current working directory.\n" +
"- **Formatting**: Use backticks for file names, commands, and symbol names. When citing code, use the form `path:startLine-endLine` (e.g. `src/app.ts:12-15`).\n" +
"- You can create reusable skills with `create_skill` when you discover a repeating pattern.\n" +
"- Be concise and helpful. If unsure, say so."
);

Expand Down
Loading