Skip to content
Merged
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: 7 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
# LightHeart OpenClaw
# Android Framework

**A methodology for building persistent AI agent teams that actually work.**
**Operations toolkit for persistent LLM agents — process watchdog, session cleanup, memory reset, API cost monitoring, and tool call proxy.**

Patterns, tools, and battle-tested operational knowledge for running AI agents
that stay up for hours, days, and weeks — coordinating with each other, learning
from failures, and shipping real software. Built from production experience
running 3+ agents 24/7 on local hardware.
Framework-agnostic patterns born from the Android Collective: 3 AI agents, 3,464 commits, 8 days. Built for OpenClaw, works with any agent stack.

About 70% of this repository is framework-agnostic. The patterns for identity,
memory, coordination, autonomy, and observability apply to any agent system —
Expand Down Expand Up @@ -131,8 +128,8 @@ For the rationale behind every design choice: **[docs/DESIGN-DECISIONS.md](docs/
### Option 1: Full Install (Session Cleanup + Proxy)

```bash
git clone https://github.com/Light-Heart-Labs/LightHeart-OpenClaw.git
cd LightHeart-OpenClaw
git clone https://github.com/Light-Heart-Labs/Android-Framework.git
cd Android-Framework

# Edit config for your setup
nano config.yaml
Expand Down Expand Up @@ -335,7 +332,7 @@ See [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) for the full deep dive.
## Project Structure

```
LightHeart-OpenClaw/
Android-Framework/
├── config.yaml # Configuration (edit this first)
├── install.sh # Linux installer
├── install.ps1 # Windows installer
Expand Down Expand Up @@ -474,4 +471,4 @@ Apache 2.0 — see [LICENSE](LICENSE)

---

Built from production experience by [Lightheart Labs](https://github.com/Light-Heart-Labs) and the [OpenClaw Collective](COLLECTIVE.md). The patterns were discovered by the agents. The docs were written by the agents. The lessons were learned the hard way.
Built from production experience by [Lightheart Labs](https://github.com/Light-Heart-Labs) and the [Android Collective](COLLECTIVE.md). The patterns were discovered by the agents. The docs were written by the agents. The lessons were learned the hard way.
4 changes: 2 additions & 2 deletions config.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# LightHeart OpenClaw - Configuration
# https://github.com/Light-Heart-Labs/LightHeart-OpenClaw
# Android Framework - Configuration
# https://github.com/Light-Heart-Labs/Android-Framework

# ─────────────────────────────────────────────
# Session Cleanup Settings
Expand Down
2 changes: 1 addition & 1 deletion docs/PATTERNS.md
Original file line number Diff line number Diff line change
Expand Up @@ -295,4 +295,4 @@ The patterns compose well. Each addresses a different failure mode, and each is

---

*These patterns will evolve. If you discover improvements, [open an issue](https://github.com/Light-Heart-Labs/LightHeart-OpenClaw/issues).*
*These patterns will evolve. If you discover improvements, [open an issue](https://github.com/Light-Heart-Labs/Android-Framework/issues).*
4 changes: 2 additions & 2 deletions guardian/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ sudo dnf install python3 curl iproute e2fsprogs psmisc

```bash
# Clone (or copy the guardian/ directory)
git clone https://github.com/Light-Heart-Labs/LightHeart-OpenClaw.git
cd LightHeart-OpenClaw/guardian
git clone https://github.com/Light-Heart-Labs/Android-Framework.git
cd Android-Framework/guardian

# Copy and edit the config
cp guardian.conf.example guardian.conf
Expand Down
14 changes: 7 additions & 7 deletions install.ps1
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# ═══════════════════════════════════════════════════════════════
# LightHeart OpenClaw - Windows Installer
# https://github.com/Light-Heart-Labs/LightHeart-OpenClaw
# Android Framework - Windows Installer
# https://github.com/Light-Heart-Labs/Android-Framework
#
# Usage:
# .\install.ps1 # Interactive install
Expand Down Expand Up @@ -34,7 +34,7 @@ function Err($msg) { Write-Host "[FAIL] $msg" -ForegroundColor Red }
# ── Banner ─────────────────────────────────────────────────────
Write-Host ""
Write-Host "===========================================================" -ForegroundColor Cyan
Write-Host " LightHeart OpenClaw - Windows Installer" -ForegroundColor Cyan
Write-Host " Android Framework - Windows Installer" -ForegroundColor Cyan
Write-Host "===========================================================" -ForegroundColor Cyan
Write-Host ""

Expand Down Expand Up @@ -145,7 +145,7 @@ $TokenSpyTaskName = "OpenClawTokenSpy"

# ── Uninstall ──────────────────────────────────────────────────
if ($Uninstall) {
Info "Uninstalling LightHeart OpenClaw..."
Info "Uninstalling Android Framework..."

# Remove scheduled task
if (Get-ScheduledTask -TaskName $CleanupTaskName -ErrorAction SilentlyContinue) {
Expand Down Expand Up @@ -209,7 +209,7 @@ if (-not $ProxyOnly -and -not $TokenSpyOnly) {
$CleanupScript = Join-Path $OpenClawDir "session-cleanup.ps1"

$cleanupContent = @"
# LightHeart OpenClaw - Session Cleanup (Windows)
# Android Framework - Session Cleanup (Windows)
# Auto-generated by install.ps1

`$SessionsDir = "$SessionsDir"
Expand Down Expand Up @@ -297,7 +297,7 @@ Write-Output "[`$(Get-Date)] Cleanup complete: removed `$removedInactive inactiv
$settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -StartWhenAvailable
$principal = New-ScheduledTaskPrincipal -UserId $env:USERNAME -LogonType S4U -RunLevel Limited

Register-ScheduledTask -TaskName $CleanupTaskName -Action $action -Trigger $trigger -Settings $settings -Principal $principal -Description "LightHeart OpenClaw - Cleanup every ${IntervalMinutes}min" | Out-Null
Register-ScheduledTask -TaskName $CleanupTaskName -Action $action -Trigger $trigger -Settings $settings -Principal $principal -Description "Android Framework - Cleanup every ${IntervalMinutes}min" | Out-Null
Ok "Scheduled task created: $CleanupTaskName (every ${IntervalMinutes}min)"
}

Expand Down Expand Up @@ -390,7 +390,7 @@ SESSION_CHAR_LIMIT=$TsSessionCharLimit
$tsTrigger = New-ScheduledTaskTrigger -AtLogOn
$tsSettings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -StartWhenAvailable -ExecutionTimeLimit (New-TimeSpan -Days 365)

Register-ScheduledTask -TaskName $TokenSpyTaskName -Action $tsAction -Trigger $tsTrigger -Settings $tsSettings -Description "LightHeart OpenClaw - Token Spy on :$TsPort" | Out-Null
Register-ScheduledTask -TaskName $TokenSpyTaskName -Action $tsAction -Trigger $tsTrigger -Settings $tsSettings -Description "Android Framework - Token Spy on :$TsPort" | Out-Null
Ok "Scheduled task created: $TokenSpyTaskName (starts at logon)"

# Start it now
Expand Down
8 changes: 4 additions & 4 deletions install.sh
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/bin/bash
# ═══════════════════════════════════════════════════════════════
# LightHeart OpenClaw - Installer
# https://github.com/Light-Heart-Labs/LightHeart-OpenClaw
# Android Framework - Installer
# https://github.com/Light-Heart-Labs/Android-Framework
#
# Usage:
# ./install.sh # Interactive install
Expand Down Expand Up @@ -61,7 +61,7 @@ done
# ── Banner ─────────────────────────────────────────────────────
echo ""
echo -e "${CYAN}═══════════════════════════════════════════════════════════${NC}"
echo -e "${CYAN} LightHeart OpenClaw - Installer${NC}"
echo -e "${CYAN} Android Framework - Installer${NC}"
echo -e "${CYAN}═══════════════════════════════════════════════════════════${NC}"
echo ""

Expand Down Expand Up @@ -161,7 +161,7 @@ echo ""

# ── Uninstall ──────────────────────────────────────────────────
if [ "$UNINSTALL" = true ]; then
info "Uninstalling LightHeart OpenClaw..."
info "Uninstalling Android Framework..."

if systemctl is-active --quiet openclaw-session-cleanup.timer 2>/dev/null; then
sudo systemctl stop openclaw-session-cleanup.timer
Expand Down
4 changes: 2 additions & 2 deletions memory-shepherd/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ Each reset cycle:

```bash
# Clone the repo
git clone https://github.com/Light-Heart-Labs/LightHeart-OpenClaw.git
cd LightHeart-OpenClaw/memory-shepherd
git clone https://github.com/Light-Heart-Labs/Android-Framework.git
cd Android-Framework/memory-shepherd

# Create your config from the example
cp memory-shepherd.conf.example memory-shepherd.conf
Expand Down
4 changes: 2 additions & 2 deletions scripts/session-cleanup.sh
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/bin/bash
# ═══════════════════════════════════════════════════════════════
# LightHeart OpenClaw - Session Cleanup Script
# https://github.com/Light-Heart-Labs/LightHeart-OpenClaw
# Android Framework - Session Cleanup Script
# https://github.com/Light-Heart-Labs/Android-Framework
#
# Prevents context overflow crashes by automatically managing
# session file lifecycle. When a session file exceeds the size
Expand Down
8 changes: 4 additions & 4 deletions scripts/vllm-tool-proxy.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
"""
LightHeart OpenClaw — vLLM Tool Call Proxy (v4)
Android Framework — vLLM Tool Call Proxy (v4)

Bridges OpenClaw with local vLLM instances by handling three incompatibilities:

Expand Down Expand Up @@ -479,7 +479,7 @@ def health():
@app.route('/')
def root():
return {
'service': 'LightHeart OpenClaw — vLLM Tool Call Proxy',
'service': 'Android Framework — vLLM Tool Call Proxy',
'version': 'v4',
'vllm_url': VLLM_URL,
'features': [
Expand All @@ -499,7 +499,7 @@ def root():
# ═══════════════════════════════════════════════════════════════

if __name__ == '__main__':
parser = argparse.ArgumentParser(description='LightHeart OpenClaw — vLLM Tool Call Proxy')
parser = argparse.ArgumentParser(description='Android Framework — vLLM Tool Call Proxy')
parser.add_argument('--port', type=int, default=int(os.environ.get('PROXY_PORT', '8003')),
help='Port to listen on (default: 8003, env: PROXY_PORT)')
parser.add_argument('--vllm-url', type=str, default=VLLM_URL,
Expand All @@ -508,6 +508,6 @@ def root():
help='Host to bind to (default: 0.0.0.0)')
args = parser.parse_args()
VLLM_URL = args.vllm_url
logger.info(f'Starting LightHeart OpenClaw vLLM Tool Call Proxy v4')
logger.info(f'Starting Android Framework vLLM Tool Call Proxy v4')
logger.info(f'Listening on {args.host}:{args.port} -> {VLLM_URL}')
app.run(host=args.host, port=args.port, threaded=True)
2 changes: 1 addition & 1 deletion systemd/openclaw-session-cleanup.service
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[Unit]
Description=LightHeart OpenClaw - Session Cleanup
Description=Android Framework - Session Cleanup
After=network.target docker.service

[Service]
Expand Down
2 changes: 1 addition & 1 deletion systemd/openclaw-session-cleanup.timer
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[Unit]
Description=LightHeart OpenClaw - Session Cleanup every __INTERVAL__ minutes
Description=Android Framework - Session Cleanup every __INTERVAL__ minutes

[Timer]
OnBootSec=__BOOT_DELAY__min
Expand Down
2 changes: 1 addition & 1 deletion systemd/token-spy@.service
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[Unit]
Description=LightHeart OpenClaw - Token Spy (%i)
Description=Android Framework - Token Spy (%i)
After=network.target

[Service]
Expand Down
2 changes: 1 addition & 1 deletion systemd/vllm-tool-proxy.service
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[Unit]
Description=LightHeart OpenClaw - vLLM Tool Call Proxy
Description=Android Framework - vLLM Tool Call Proxy
After=network.target docker.service
Wants=docker.service

Expand Down
Loading