Event-driven AI Agent Runtime for Discord, Telegram, GitHub, and the local terminal
Language: English (primary / canonical) · 繁體中文 (translation)
Fork differences · Quick start · Surfaces · Full documentation · Architecture details
Lilac Core is the Redis-backed, event-driven runtime for Discord, Telegram, and optional GitHub ingress. It owns surface routing, agent execution, output relays, durable workflows, and the internal HTTP tool server.Architecture and ownership are documented in PROJECT.md. Repository rules for coding agents are in AGENTS.md.
Important
This is a downstream fork that continuously tracks stanley2058/lilac-mono through Git history and the upstream remote. It is not an official upstream release. This project regularly merges upstream updates while maintaining independent Telegram, OpenAI-compatible image routing, GitHub reply permalink, and deployment automation features.
Lilac brings platform messaging, routing, model execution, tools, Skills, and recoverable workflows into one runtime.
The table below lists only behavior that still differs from upstream. For the full rationale, limitations, and items reported back upstream, see docs/fork-differences.md.
| Area | Difference provided by this fork | Important limitations |
|---|---|---|
| Telegram surface | DMs, groups, forum topics, streaming HTML replies, cancellation, reactions, command menu, inbound/outbound attachments, workflow cards, and same-surface tools | Disabled by default; long polling only |
| OpenAI-compatible image routing | Routes the existing generate.image aliases through a single operator-specified OpenAI-compatible endpoint |
configVersion: 2 only; no automatic fallback or custom alias mapping |
| GitHub reply UX | In reply to can link directly to an issue/PR body or a specified comment's canonical permalink |
GitHub comment self-loop protection has been accepted upstream and is no longer fork-only |
| Custom media plugin | Deployable Level 2 image/video plugin example demonstrating strict configuration and file-safety handling | The plugin is trusted in-process code; restricted callers currently cannot use external callables |
| Operations and delivery | Upstream checks every 6 hours and GHCR publishes verified catalina/claudia tags |
Automatic merges still require manual handling when conflicts occur |
flowchart LR
Discord[Discord] --> Bus[Typed Redis Streams bus]
Telegram[Telegram] --> Bus
Bus --> Router[Surface router]
GitHub[GitHub webhook] --> Request[Request queue]
Router --> Request
Request --> Agent[Agent runner]
Agent --> L1[Level 1 local tools]
Agent --> L2[Level 2 HTTP tools]
Agent --> Skills[Level 3 skills]
Agent --> Output[Request-scoped output]
Output --> Discord
Output --> Telegram
Output --> GitHub
Workflow[Durable workflow engine] <--> Request
Core platform adapters send events to the typed bus. The router creates or updates a request, and the agent runner executes it using models, tools, and Skills. The output relay then sends the result back to the originating surface. GitHub webhooks can create requests directly.
The durable workflow engine uses the same request bus and stores trigger, wait, sleep, subagent, and recovery information in a SQLite journal. See PROJECT.md for the complete topics, queue modes, permissions, and startup/shutdown order.
flowchart LR
Upstream[stanley2058/lilac-mono main] -->|scheduled check every 6 hours| Sync[Sync Upstream workflow]
Sync -->|clean merge| Fork[DF-wu/lilac-mono main]
Features[Fork features and fixes] --> Fork
Fork --> CI[CI]
Fork --> Images[GHCR image workflow]
Requirements: Docker Compose, Bun 1.3.14, a valid DISCORD_TOKEN, and at least one model provider credential matching the models.main configuration. Core still connects to Discord at startup; the Discord token remains required even when using only Telegram, GitHub, or the tool server. All surface allowlists remain fail-closed.
git clone https://github.com/DF-wu/lilac-mono.git
cd lilac-mono
bun install
cp .env.example .env
chmod 600 .env
mkdir -p data
cp packages/utils/config-templates/core-config.example.yaml data/core-config.yaml
cat > compose.override.yaml <<'YAML'
services:
lilac:
env_file:
- .env
YAMLBefore starting, complete these two steps:
- Set
DISCORD_TOKENand the credential for the model provider selected indata/core-config.yamlin.env. Stockcompose.yamldoes not pass provider credentials; thecompose.override.yamlabove explicitly passes.envthroughenv_file. - Configure the Discord allowlist in
data/core-config.yaml, and enable and restrict any other surfaces you plan to use.
docker compose up -d --build --wait --wait-timeout 120
bun run docker:verify
docker compose ps
curl -fsS http://localhost:8080/readyzcompose.yaml also starts Redis and mounts ./data at /data. See docs/docker-deployment.md for production deployment, operator tokens, UID, persistence, and diagnostics.
Warning
Core's tool server has no general-purpose public HTTP authentication. Keep 8080 on a trusted host or network boundary; do not expose it directly to the public internet.
Install the dependencies and prepare a reachable Redis instance:
bun install
docker run --rm -d --name lilac-source-redis -p 127.0.0.1:6380:6379 redis:7-alpine
export REDIS_URL=redis://127.0.0.1:6380
export DATA_DIR="$PWD/data"
export LL_TOOL_SERVER_PORT=8080
bun apps/core/src/runtime/main.tsCore requires REDIS_URL, DISCORD_TOKEN, and a valid model configuration. Telegram and GitHub may remain disabled, but the Discord adapter still connects when Core starts; leave the Discord allowlist empty to ignore all Discord traffic.
| Surface | Minimum configuration | Default protection | Documentation |
|---|---|---|---|
| Discord | DISCORD_TOKEN; configure allowedChannelIds or allowedGuildIds |
Ignores all Discord traffic when both allowlists are empty | core-config.example.yaml |
| Telegram | configVersion: 2, enabled: true, token, allowedChatIds |
Disabled by default; ignores all chats when the chat allowlist is empty | docs/telegram-surface.md |
| GitHub | GitHub App auth, GITHUB_WEBHOOK_SECRET, and an HTTPS/reverse proxy reachable by GitHub; a user token is an optional preferred outbound identity |
The surface does not start without the GitHub App secret; returns 401 for an invalid signature |
docs/github-reply-permalinks.md |
The GitHub webhook listens on port 8787 and path /github/webhook by default. Stock Compose does not forward or expose the GitHub webhook environment and port, so production deployments must provide the reverse proxy, environment, and network wiring themselves.
The webhook secret only verifies inbound requests; the runtime currently uses the GitHub App secret as the condition for enabling the entire surface. Set up the App first, then add a user token as the preferred outbound identity if needed. Use operator-only onboarding to inspect both parameters:
docker compose exec -T lilac /usr/local/bin/tools --operator --help onboarding.github_app
docker compose exec -T lilac /usr/local/bin/tools --operator --help onboarding.github_user_tokenTelegram supports the full conversation path, workflow cards, and same-surface tools, but its platform capabilities are not identical to Discord. See Telegram feature status for differences in inbound media, history, reactions, and search.
Core divides agent capabilities into three levels:
- Level 1: Run-local tools such as
bash, file I/O, search, patch, batch, and subagent delegation. - Level 2: Callables provided by the HTTP tool server, including web, surface, workflow, MCP, attachments, generation, and SSH.
- Level 3:
SKILL.mdbundles discovered on disk and loaded on demand.
Build and use the tools CLI:
cd apps/tool-bridge
bun run build
./dist/index.js --list
./dist/index.js --help workflow.run.listConnect to another backend:
TOOL_SERVER_BACKEND_URL=http://host:8080 ./apps/tool-bridge/dist/index.js --listExternal plugins go in DATA_DIR/plugins/<plugin-id>/. They run in the same process as Core and have the Core process's permissions; read PLUGIN_AUTHORING.md before developing one.
configVersion: 2
surface:
telegram:
enabled: true
token: replace-with-botfather-token
allowedChatIds:
- "1001"Keep data/core-config.yaml private because it contains the bot token:
chmod 600 data/core-config.yamldocker compose up -d --wait --wait-timeout 120
curl -s localhost:8080/readyz | jq '.checks[] | select(.name == "telegram.ready")'See docs/telegram-surface.md for group privacy mode, forum topic session IDs, streaming, the command menu, and troubleshooting.
configVersion: 2
tools:
generate:
image:
provider: openai-compatibleFor Docker Compose, put the endpoint and credential in .env, which is loaded by compose.override.yaml:
OPENAI_COMPATIBLE_BASE_URL=https://provider.example.com/v1
OPENAI_COMPATIBLE_API_KEY=replace-with-api-keyThen recreate the container:
docker compose up -d --force-recreate --wait --wait-timeout 120 lilacWhen running from source, export the variables with the same names before starting Core.
See docs/generate-image-openai-compatible.md for aliases, the openaiCompatible.models allowlist and openaiCompatible.modelIds overrides, generation/edit endpoints, the absence of fallback behavior, and colon-form size aspect-ratio forwarding.
mkdir -p data/plugins
cp -R examples/plugins/custom-media data/plugins/custom-media
docker compose restart lilac
docker compose up -d --wait --wait-timeout 120 lilac
docker compose exec -T lilac /usr/local/bin/tools --operator --list
docker compose exec -T lilac /usr/local/bin/tools --operator --help custom-media.imageSee examples/plugins/custom-media/README.md for the complete build, credential, model, and file-safety contract.
| Path | Purpose |
|---|---|
apps/core/ |
Redis-backed Core runtime and all surface, workflow, and tool wiring |
apps/tool-bridge/ |
tools CLI and standalone tool-server entrypoint |
apps/installer/ |
Guided Docker setup and reconfiguration CLI |
apps/computer-use-gateway/ |
Optional authenticated desktop-session gateway |
packages/event-bus/ |
Typed Redis Streams contract and transport |
packages/agent/ |
AI SDK streaming, steering, follow-up, and interrupt control |
packages/plugin-runtime/ |
Level 1/Level 2 plugin contract |
packages/utils/ |
Config, providers, prompts, and Skills |
data/ |
Core local runtime state; do not commit secrets |
ref/ |
Vendored/reference repositories; subject to their respective licenses and treated as read-only |
This repo uses Bun workspaces:
bun install
bun run cibun run ci checks codegen, lint, root/workspace tests, TypeScript, and formatting in sequence. Common individual commands:
bun run check
bun run ci
bun run test:core
bun run test:all
bun run typecheck
bun run lint
bun run fmt:checkbun run check runs the concurrent local repository gates; bun run ci runs the conservative serial CI sequence. The full suite includes the permanent architecture and production-syntax gates.
See AGENTS.md for each workspace's build, test, and typecheck commands; see PROJECT.md for project terminology and the complete architecture.
.github/workflows/sync-upstream.yml checks upstream main every 6 hours and attempts to merge new commits into this fork's main. A clean merge triggers an image build; maintainers handle conflicts manually.
- Report new fork features, deployment workflows, Telegram issues, or OpenAI-compatible image-routing issues in
DF-wu/lilac-mono. - For an issue reproducible without fork modifications, first confirm the upstream state, then report it to
stanley2058/lilac-mono. - Features historically contributed by this fork and accepted upstream are no longer listed as current differences. See
docs/fork-differences.mdfor the list.
PROJECT.md: durable architecture, terminology, ownership, and where-to-change guidecore-config.example.yaml: current Core configuration referencedocs/core-config-migrations.md: manual Core config upgradesplan/README.md: active implementation plansMIGRATIONS.md: persisted-data, wire, and protocol migrationsdocs/README.md: deployment, surface, fork-feature, and extension indexdocs/installation.md: guided installation, providers, and reconfigurationdocs/docker-deployment.md: container deployment and diagnosticsdocs/computer-use.md: optional desktop gateway and runner deploymentdocs/claude-code.md: Claude Code authentication, tools, continuation, and storagedocs/skill-authoring.md: skill format, discovery, and authoring guidancePLUGIN_AUTHORING.md: Core tool plugin contract
This repository is released under the MIT License, retaining the original upstream authors' copyright and license text.
Thanks to stanley2058/lilac-mono for the original design and continued development. This fork has no affiliation with or official endorsement from the upstream maintainers.
Vendored/reference material in ref/ is subject to its original license terms.