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
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,23 @@ URL in Slack. If you have a fixed ngrok domain, run
ignore that HTTPS override and keep using the local loopback callback,
`http://127.0.0.1:53682/callback`.

Export OpenWiki as skills for a host coding agent:

```sh
openwiki integration claude
openwiki integration claude ../other-repo
```

`openwiki integration claude [path]` scaffolds two Claude Code skills,
`openwiki-init` and `openwiki-update`, into `.claude/skills/` in the target
repository (defaulting to the current directory). Unlike the other commands,
this one needs **no model provider or API key** — Claude Code itself is the
engine. Open the repository in Claude Code and run `/openwiki-init` to generate
the initial docs under `openwiki/`, then `/openwiki-update` after source changes
to refresh them. Each slash command accepts an optional repository path
argument. This covers code mode (repository docs) only; the personal brain and
connectors still require the OpenWiki runtime.

Bare `openwiki` runs in code mode for the current repository. It creates initial repository documentation in `openwiki/` when no wiki exists. Use `openwiki personal` for the local general-purpose wiki in `~/.openwiki/wiki/`. By default, the CLI stays open after each run so you can send follow-up messages. Use `-p` or `--print` for a one-shot non-interactive run that prints the final assistant output.

Bare `openwiki --init` and `openwiki --update` default to code mode and operate on repository documentation. Use the `personal` positional mode or `--mode personal` to initialize or update the local personal brain wiki.
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"files": [
"dist",
"skills",
"templates",
"README.md",
"LICENSE"
],
Expand Down
36 changes: 36 additions & 0 deletions src/cli.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import {
runOpenWikiIngestion,
type OpenWikiIngestionResult,
} from "./ingestion.js";
import { getIntegrationWriter } from "./integrations/index.js";
import {
readOpenWikiOnboardingConfig,
saveOpenWikiOnboardingConfig,
Expand Down Expand Up @@ -3489,6 +3490,8 @@ if (command.kind === "auth") {
await runCronCommand(command);
} else if (command.kind === "ingest") {
await runIngestCommand(command);
} else if (command.kind === "integration") {
await runIntegrationCommand(command);
} else if (shouldPrintStartupError(argv, parsedCommand, command)) {
process.stderr.write(`${command.message}\n`);
process.exitCode = command.exitCode;
Expand Down Expand Up @@ -3742,6 +3745,39 @@ async function runIngestCommand(
}
}

async function runIntegrationCommand(
command: Extract<CliCommand, { kind: "integration" }>,
): Promise<void> {
try {
const writer = getIntegrationWriter(command.agent);

if (!writer) {
throw new Error(`Unsupported integration agent: ${command.agent}`);
}

const result = await writer(command.targetPath);

process.stdout.write(
`Scaffolded OpenWiki ${command.agent} skills into ${result.targetDir}\n`,
);
for (const filePath of result.writtenFiles) {
process.stdout.write(` ${filePath}\n`);
}

if (result.nextSteps.length > 0) {
process.stdout.write("\nNext steps\n");
for (const step of result.nextSteps) {
process.stdout.write(` - ${step}\n`);
}
}

process.exitCode = 0;
} catch (error) {
process.stderr.write(`${getErrorMessage(error)}\n`);
process.exitCode = 1;
}
}

async function runAuthCommand(
command: Extract<CliCommand, { kind: "auth" }>,
): Promise<void> {
Expand Down
69 changes: 69 additions & 0 deletions src/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ import type { OpenWikiCommand } from "./agent/types.js";
import { isAuthProviderId } from "./auth/providers.js";
import type { AuthProviderId } from "./auth/types.js";
import { parseIngestionTarget, type IngestionTarget } from "./ingestion.js";
import {
isSupportedIntegrationAgent,
supportedIntegrationAgents,
} from "./integrations/index.js";

export type HelpRow = {
label: string;
Expand Down Expand Up @@ -52,6 +56,12 @@ export type CliCommand =
exitCode: 0;
target: CronTarget | null;
}
| {
kind: "integration";
agent: string;
exitCode: 0;
targetPath: string;
}
| { kind: "help"; exitCode: 0 }
| {
kind: "run";
Expand Down Expand Up @@ -321,6 +331,57 @@ export function parseCommand(argv: string[]): CliCommand {
}
}

if (argv[0] === "integration") {
const agent = argv[1];
const supported = supportedIntegrationAgents().join(", ");

if (!agent) {
return {
kind: "error",
exitCode: 1,
message: `Usage: openwiki integration <agent> [path]. Supported agents: ${supported}.`,
};
}

if (!isSupportedIntegrationAgent(agent)) {
return {
kind: "error",
exitCode: 1,
message: `Unknown integration agent: ${agent}. Supported agents: ${supported}.`,
};
}

let targetPath = ".";
let hasPath = false;
for (const arg of argv.slice(2)) {
if (arg.startsWith("-")) {
return {
kind: "error",
exitCode: 1,
message: `Unknown option for integration: ${arg}`,
};
}

if (hasPath) {
return {
kind: "error",
exitCode: 1,
message: "Usage: openwiki integration <agent> [path]",
};
}

targetPath = arg;
hasPath = true;
}

return {
kind: "integration",
agent,
exitCode: 0,
targetPath,
};
}

if (isOpenWikiRunMode(argv[0])) {
return parseRunCommand(argv.slice(1), argv[0], "positional");
}
Expand Down Expand Up @@ -598,6 +659,7 @@ export const helpContent: HelpContent = {
"openwiki cron resume <source|all>",
"openwiki cron delete <source|all>",
"openwiki ngrok start [url] [--port <port>]",
"openwiki integration <agent> [path]",
],
commands: [
{
Expand Down Expand Up @@ -658,6 +720,11 @@ export const helpContent: HelpContent = {
description:
"Start an ngrok tunnel for Slack OAuth, optionally using a fixed HTTPS URL.",
},
{
label: "openwiki integration <agent> [path]",
description:
"Scaffold host-agent skills (openwiki-init, openwiki-update) into a repo so the agent maintains openwiki/ docs itself. No model provider or API key needed. Supports claude.",
},
],
options: [
{
Expand Down Expand Up @@ -715,6 +782,8 @@ export const helpContent: HelpContent = {
"openwiki auth tools notion",
"openwiki ngrok start",
"openwiki ngrok start https://openwiki.ngrok.app",
"openwiki integration claude",
"openwiki integration claude ../other-repo",
],
developmentExamples: ["openwiki --dry-run"],
};
Expand Down
Loading