indieclaw 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. indieclaw-0.1.0/.bandit +2 -0
  2. indieclaw-0.1.0/.env.example +4 -0
  3. indieclaw-0.1.0/.github/workflows/ci.yml +43 -0
  4. indieclaw-0.1.0/.github/workflows/python-doctor.yml +54 -0
  5. indieclaw-0.1.0/.github/workflows/release.yml +93 -0
  6. indieclaw-0.1.0/.gitignore +11 -0
  7. indieclaw-0.1.0/.python-version +1 -0
  8. indieclaw-0.1.0/CHANGELOG.md +15 -0
  9. indieclaw-0.1.0/CLAUDE.md +67 -0
  10. indieclaw-0.1.0/LICENSE +21 -0
  11. indieclaw-0.1.0/Makefile +44 -0
  12. indieclaw-0.1.0/PKG-INFO +117 -0
  13. indieclaw-0.1.0/README.md +94 -0
  14. indieclaw-0.1.0/deploy.sh +13 -0
  15. indieclaw-0.1.0/docs/index.html +265 -0
  16. indieclaw-0.1.0/indieclaw/__init__.py +6 -0
  17. indieclaw-0.1.0/indieclaw/agent.py +446 -0
  18. indieclaw-0.1.0/indieclaw/auth.py +36 -0
  19. indieclaw-0.1.0/indieclaw/browser.py +210 -0
  20. indieclaw-0.1.0/indieclaw/claude_code.py +651 -0
  21. indieclaw-0.1.0/indieclaw/config.py +72 -0
  22. indieclaw-0.1.0/indieclaw/daemon.py +81 -0
  23. indieclaw-0.1.0/indieclaw/doctor.py +419 -0
  24. indieclaw-0.1.0/indieclaw/handlers.py +620 -0
  25. indieclaw-0.1.0/indieclaw/handlers_commands.py +279 -0
  26. indieclaw-0.1.0/indieclaw/main.py +491 -0
  27. indieclaw-0.1.0/indieclaw/prompt_builder.py +100 -0
  28. indieclaw-0.1.0/indieclaw/py.typed +0 -0
  29. indieclaw-0.1.0/indieclaw/scheduler.py +296 -0
  30. indieclaw-0.1.0/indieclaw/session_state.py +78 -0
  31. indieclaw-0.1.0/indieclaw/setup.py +403 -0
  32. indieclaw-0.1.0/indieclaw/setup_services.py +210 -0
  33. indieclaw-0.1.0/indieclaw/skills.py +17 -0
  34. indieclaw-0.1.0/indieclaw/subconscious.py +100 -0
  35. indieclaw-0.1.0/indieclaw/tool_loader.py +136 -0
  36. indieclaw-0.1.0/indieclaw/tools.py +131 -0
  37. indieclaw-0.1.0/indieclaw/tools_browser.py +90 -0
  38. indieclaw-0.1.0/indieclaw/tools_sdk.py +525 -0
  39. indieclaw-0.1.0/indieclaw/tui.py +287 -0
  40. indieclaw-0.1.0/indieclaw/version.py +126 -0
  41. indieclaw-0.1.0/indieclaw/watchdog.sh +113 -0
  42. indieclaw-0.1.0/indieclaw/workspace.py +97 -0
  43. indieclaw-0.1.0/install.sh +73 -0
  44. indieclaw-0.1.0/pyproject.toml +65 -0
  45. indieclaw-0.1.0/pyrightconfig.json +5 -0
  46. indieclaw-0.1.0/templates/AGENT.md +89 -0
  47. indieclaw-0.1.0/templates/MEMORY.md +16 -0
  48. indieclaw-0.1.0/templates/SOUL.md +34 -0
  49. indieclaw-0.1.0/templates/SUBCONSCIOUS.md +37 -0
  50. indieclaw-0.1.0/templates/USER.md +21 -0
  51. indieclaw-0.1.0/templates/crons.yaml +18 -0
  52. indieclaw-0.1.0/templates/skills/cli-learning/SKILL.md +51 -0
  53. indieclaw-0.1.0/templates/skills/handover/SKILL.md +21 -0
  54. indieclaw-0.1.0/templates/skills/skill-creation/SKILL.md +22 -0
  55. indieclaw-0.1.0/templates/skills/tool-building/SKILL.md +77 -0
  56. indieclaw-0.1.0/tests/test_agent.py +367 -0
  57. indieclaw-0.1.0/tests/test_auth.py +87 -0
  58. indieclaw-0.1.0/tests/test_config.py +187 -0
  59. indieclaw-0.1.0/tests/test_daemon.py +112 -0
  60. indieclaw-0.1.0/tests/test_doctor.py +551 -0
  61. indieclaw-0.1.0/tests/test_handlers.py +586 -0
  62. indieclaw-0.1.0/tests/test_scheduler.py +146 -0
  63. indieclaw-0.1.0/tests/test_session_state.py +95 -0
  64. indieclaw-0.1.0/tests/test_skills.py +58 -0
  65. indieclaw-0.1.0/tests/test_subconscious.py +126 -0
  66. indieclaw-0.1.0/tests/test_tool_loader.py +188 -0
  67. indieclaw-0.1.0/tests/test_tools.py +53 -0
  68. indieclaw-0.1.0/tests/test_tools_sdk.py +341 -0
  69. indieclaw-0.1.0/tests/test_version.py +85 -0
  70. indieclaw-0.1.0/tests/test_workspace.py +52 -0
  71. indieclaw-0.1.0/uv.lock +1686 -0
@@ -0,0 +1,2 @@
1
+ [bandit]
2
+ skips = B404,B603,B607,B108
@@ -0,0 +1,4 @@
1
+ TELEGRAM_BOT_TOKEN=your-telegram-bot-token
2
+ ALLOWED_USER_IDS=your-telegram-chat-id
3
+ INDIECLAW_MODEL=anthropic/claude-sonnet-4-6
4
+ ANTHROPIC_API_KEY=your-anthropic-api-key
@@ -0,0 +1,43 @@
1
+ name: CI
2
+ on: [push, pull_request]
3
+ jobs:
4
+ test:
5
+ runs-on: ubuntu-latest
6
+ strategy:
7
+ matrix:
8
+ python-version: ["3.12", "3.13"]
9
+ steps:
10
+ - uses: actions/checkout@v4
11
+ - uses: astral-sh/setup-uv@v4
12
+ - run: uv python install ${{ matrix.python-version }}
13
+ - run: uv sync --dev
14
+ - run: uv run pytest tests/ -v
15
+
16
+ auto-release:
17
+ needs: test
18
+ if: github.ref == 'refs/heads/main' && github.event_name == 'push' && contains(github.event.head_commit.message, 'Bump version')
19
+ runs-on: ubuntu-latest
20
+ permissions:
21
+ contents: write
22
+ steps:
23
+ - uses: actions/checkout@v4
24
+
25
+ - name: Extract version
26
+ id: version
27
+ run: |
28
+ VERSION=$(python3 -c "import re; print(re.search(r'version\s*=\s*\"([^\"]+)\"', open('pyproject.toml').read()).group(1))")
29
+ echo "version=$VERSION" >> "$GITHUB_OUTPUT"
30
+ echo "tag=v$VERSION" >> "$GITHUB_OUTPUT"
31
+
32
+ - name: Create tag and release
33
+ env:
34
+ GH_TOKEN: ${{ github.token }}
35
+ run: |
36
+ TAG="${{ steps.version.outputs.tag }}"
37
+ if gh release view "$TAG" >/dev/null 2>&1; then
38
+ echo "Release $TAG already exists, skipping."
39
+ exit 0
40
+ fi
41
+ git tag "$TAG"
42
+ git push origin "$TAG"
43
+ gh release create "$TAG" --generate-notes -t "$TAG"
@@ -0,0 +1,54 @@
1
+ name: Python Doctor
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+
7
+ permissions:
8
+ contents: write
9
+
10
+ jobs:
11
+ health-check:
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - uses: actions/checkout@v4
15
+
16
+ - name: Install python-doctor
17
+ run: pipx install python-doctor
18
+
19
+ - name: Run python-doctor
20
+ id: doctor
21
+ run: |
22
+ score=$(python-doctor . --score 2>/dev/null || echo "0")
23
+ echo "score=$score" >> "$GITHUB_OUTPUT"
24
+ echo "Python Doctor score: $score/100"
25
+
26
+ - name: Determine badge color
27
+ id: color
28
+ run: |
29
+ score=${{ steps.doctor.outputs.score }}
30
+ if [ "$score" -ge 90 ]; then
31
+ echo "color=brightgreen" >> "$GITHUB_OUTPUT"
32
+ elif [ "$score" -ge 75 ]; then
33
+ echo "color=green" >> "$GITHUB_OUTPUT"
34
+ elif [ "$score" -ge 50 ]; then
35
+ echo "color=yellow" >> "$GITHUB_OUTPUT"
36
+ else
37
+ echo "color=red" >> "$GITHUB_OUTPUT"
38
+ fi
39
+
40
+ - name: Update badge in README
41
+ run: |
42
+ score=${{ steps.doctor.outputs.score }}
43
+ color=${{ steps.color.outputs.color }}
44
+ encoded_score=$(echo "${score}/100" | sed 's|/|%2F|g')
45
+ sed -i "s|python--doctor-[0-9]*%2F100-[a-z]*|python--doctor-${encoded_score}-${color}|" README.md
46
+
47
+ - name: Commit if changed
48
+ run: |
49
+ git diff --quiet README.md && exit 0
50
+ git config user.name "github-actions[bot]"
51
+ git config user.email "github-actions[bot]@users.noreply.github.com"
52
+ git add README.md
53
+ git commit -m "ci: update python-doctor badge to ${{ steps.doctor.outputs.score }}/100"
54
+ git push
@@ -0,0 +1,93 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - 'v*'
7
+
8
+ jobs:
9
+ build:
10
+ name: Build binary (${{ matrix.os }} ${{ matrix.arch }})
11
+ runs-on: ${{ matrix.runner }}
12
+ strategy:
13
+ matrix:
14
+ include:
15
+ - os: linux
16
+ arch: x86_64
17
+ runner: ubuntu-latest
18
+ - os: linux
19
+ arch: arm64
20
+ runner: ubuntu-24.04-arm
21
+ - os: macos
22
+ arch: arm64
23
+ runner: macos-latest
24
+
25
+ steps:
26
+ - uses: actions/checkout@v4
27
+
28
+ - uses: astral-sh/setup-uv@v4
29
+
30
+ - name: Install Python
31
+ run: uv python install 3.12
32
+
33
+ - name: Install dependencies + PyInstaller
34
+ run: uv sync && uv pip install pyinstaller
35
+
36
+ - name: Build binary
37
+ run: |
38
+ uv run pyinstaller \
39
+ --onefile \
40
+ --name indieclaw \
41
+ --hidden-import indieclaw \
42
+ --collect-all indieclaw \
43
+ --collect-all claude_agent_sdk \
44
+ indieclaw/main.py
45
+
46
+ - name: Rename binary
47
+ run: |
48
+ mv dist/indieclaw dist/indieclaw-${{ matrix.os }}-${{ matrix.arch }}
49
+
50
+ - name: Upload artifact
51
+ uses: actions/upload-artifact@v4
52
+ with:
53
+ name: indieclaw-${{ matrix.os }}-${{ matrix.arch }}
54
+ path: dist/indieclaw-${{ matrix.os }}-${{ matrix.arch }}
55
+
56
+ pypi:
57
+ name: Publish to PyPI
58
+ runs-on: ubuntu-latest
59
+ permissions:
60
+ id-token: write
61
+
62
+ steps:
63
+ - uses: actions/checkout@v4
64
+
65
+ - uses: astral-sh/setup-uv@v4
66
+
67
+ - name: Install Python
68
+ run: uv python install 3.12
69
+
70
+ - name: Build package
71
+ run: uv build
72
+
73
+ - name: Publish to PyPI
74
+ uses: pypa/gh-action-pypi-publish@release/v1
75
+
76
+ release:
77
+ name: Create GitHub release
78
+ needs: [build, pypi]
79
+ runs-on: ubuntu-latest
80
+ permissions:
81
+ contents: write
82
+
83
+ steps:
84
+ - uses: actions/download-artifact@v4
85
+ with:
86
+ path: dist
87
+ merge-multiple: true
88
+
89
+ - name: Create GitHub release
90
+ uses: softprops/action-gh-release@v2
91
+ with:
92
+ files: dist/indieclaw-*
93
+ generate_release_notes: true
@@ -0,0 +1,11 @@
1
+ .env
2
+ *.db
3
+ __pycache__/
4
+ .venv/
5
+ memory/
6
+ *.pyc
7
+ .DS_Store
8
+ dist/
9
+ *.egg-info/
10
+ .worktrees/
11
+ docs/superpowers/
@@ -0,0 +1 @@
1
+ 3.12
@@ -0,0 +1,15 @@
1
+ # Changelog
2
+
3
+ All notable changes to IndieClaw will be documented in this file.
4
+
5
+ ## [0.1.0] - 2026-03-28
6
+
7
+ - Initial release as IndieClaw
8
+ - Self-hosted personal AI agent with Telegram integration
9
+ - Cron scheduler with configurable delivery
10
+ - Skills system with progressive disclosure
11
+ - Subconscious reflection engine
12
+ - Dynamic tool loading
13
+ - Browser automation
14
+ - Streaming responses
15
+ - fix: respect deliver_to: '' in cron jobs to prevent double delivery
@@ -0,0 +1,67 @@
1
+ # CLAUDE.md
2
+
3
+ ## Commands
4
+
5
+ ```bash
6
+ uv sync # install dev deps
7
+ uv run pytest # run tests (always run full suite before pushing)
8
+ uv run pytest tests/test_agent.py::test_run_returns_string # single test
9
+ ```
10
+
11
+ ## Architecture
12
+
13
+ Telegram bot wrapping `claude-agent-sdk`. State lives in `~/.indieclaw/` (not in this repo).
14
+
15
+ **Request flow:** Telegram message → `handlers.py` → `agent.run(chat_id, msg)` → short-lived `ClaudeSDKClient` (context manager) → tool loop → reply via Telegram.
16
+
17
+ **Session lifecycle:** Short-lived client per message. Session state persists via SDK's JSONL files; `resume=session_id` reconnects to the same conversation. `_session_ids[chat_id]` tracks the last session ID. Reset by `/reset` (clears session ID) or model/effort change. Context compaction handled natively by the SDK.
18
+
19
+ **Subagents:** Native SDK `AgentDefinition` (`task-runner`) for long autonomous tasks. Claude spawns them via the built-in `Agent` tool. No custom task registry.
20
+
21
+ **System prompt** (`prompt_builder.py`): Built per client creation. Order: workspace context → SOUL.md → USER.md → skills list → MEMORY.md. Current timestamp prepended to user message for cache-friendliness.
22
+
23
+ ## Key files
24
+
25
+ | File | What it does |
26
+ |------|-------------|
27
+ | `agent.py` | Short-lived SDK client per message, `run()`, `run_streaming()`, native subagents, hooks |
28
+ | `handlers.py` | Telegram command/message handlers, typing loop, reactions, `/update` |
29
+ | `tools_sdk.py` | Built-in SDK tools (telegram, browser, search_sessions, etc.) |
30
+ | `tool_loader.py` | Hot-loads `~/.indieclaw/tools/*.py` as SDK tools |
31
+ | `browser.py` | Playwright browser manager (lazy singleton, per-chat contexts) |
32
+ | `main.py` | CLI entrypoint, bot wiring, startup/shutdown hooks |
33
+ | `version.py` | Shared version utilities: `local_version()`, `check_remote_version()`, `get_update_summary()` |
34
+
35
+ ## Tools
36
+
37
+ **Built-in** (5): `Bash`, `Read`, `Write`, `WebSearch`, `WebFetch`
38
+
39
+ **SDK tools** (`tools_sdk.py`): `telegram_send`, `telegram_edit`, `telegram_send_file`, `telegram_send_voice`, `telegram_react`, `self_restart`, `self_update`, `update_config`, `read_skill`, `search_sessions`, `browse`, `browser_click`, `browser_type`, `browser_screenshot`, `browser_eval`, `test_tool`, `deploy_tool`, `disable_tool`, `update_subconscious`, `reflect`
40
+
41
+ **Dynamic tools** (`~/.indieclaw/tools/*.py`): Must export `SCHEMA` (OpenAI function schema dict) and `execute()`. All params arrive as strings — always coerce defensively.
42
+
43
+ ## Things that bite you
44
+
45
+ - **`/update` handler is separate from `self_update` tool.** Both call `uv tool install --upgrade` then SIGTERM for systemd restart. Version logic is shared via `version.py` — don't duplicate.
46
+ - **Tool wrapper casts ALL params to strings.** Every tool (built-in and dynamic) must defensively coerce: `int()`, `json.loads()` with try/except. Never trust types.
47
+ - **System prompt is built once per client, not per message.** Don't add per-message dynamic content to `_system_prompt()` — it breaks prompt caching. Put ephemeral info in the user message instead.
48
+ - **Dynamic tools are loaded module-level** via `reload_dynamic_tools()`, called at the start of each `run()`. Adding/modifying tools no longer resets sessions.
49
+ - **Edited messages are reprocessed.** `on_message` handles both `update.message` and `update.edited_message`. Use `update.edited_message or update.message` to get the right one.
50
+ - **Test mocks need `edited_message = None`.** MagicMock is truthy — tests that create mock Updates must explicitly set `update.edited_message = None` or the handler picks up the mock as an edit.
51
+ - **`importlib.metadata` doesn't work in uv tool installs.** `importlib.metadata.version("indieclaw")` throws `PackageNotFoundError` when installed via `uv tool install`. Use `version.local_version()` which falls back to parsing `uv tool list` output, then `pyproject.toml`.
52
+ - **Always end-to-end test before pushing, not just unit tests.** Unit tests passing doesn't mean the feature works in the real environment. For version checks, runtime metadata, or anything environment-dependent — verify the actual function output in a quick `uv run python -c "..."` smoke test.
53
+
54
+ ## What makes code maintainable
55
+
56
+ - **Reduce layers a reader has to trace.** Flat is better than deep. If understanding a change requires jumping through 3+ files or call frames, collapse the indirection. Prefer direct calls over abstract dispatch when there's only one use case.
57
+ - **Reduce state a reader has to hold in their head.** Short functions, small scopes, no hidden side effects. A reader should be able to understand a function from its signature and body alone — without needing to track what mutated elsewhere.
58
+
59
+ ## Conventions
60
+
61
+ - **TDD: write tests first, then implement.** Write a failing test that captures the expected behavior, then write the code to make it pass. This catches environment mismatches and edge cases before they ship.
62
+ - **Release:** `make release V=x.y.z` — updates `pyproject.toml` version, generates `CHANGELOG.md` from commits since last tag, runs `uv lock`, commits, and creates annotated git tag. Then `git push && git push --tags`.
63
+ - Never add co-author lines or "Generated with Claude Code" to commits.
64
+ - Run full test suite before pushing — `uv run pytest`.
65
+ - Keep `CUSTOM_TOOLS` list at the bottom of `tools_sdk.py` in sync when adding tools.
66
+ - Browser tools use lazy imports (`from .browser import BrowserManager`) to avoid importing Playwright at module load.
67
+ - **Be lean with context.** Read files with `offset`/`limit` when you only need a section. Batch related shell commands (commit + push + upgrade + restart) into one chained call. Don't re-read files you just wrote. Use parallel tool calls. Skip exploratory reads when you already know the structure.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 IndieClaw Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,44 @@
1
+ # indieclaw release automation
2
+ # Usage: make release V=0.8.0
3
+
4
+ CURRENT_VERSION := $(shell python3 -c "import re; print(re.search(r'version\s*=\s*\"([^\"]+)\"', open('pyproject.toml').read()).group(1))")
5
+
6
+ .PHONY: release version
7
+
8
+ version:
9
+ @echo $(CURRENT_VERSION)
10
+
11
+ release:
12
+ ifndef V
13
+ $(error Usage: make release V=x.y.z (current: $(CURRENT_VERSION)))
14
+ endif
15
+ @echo "Releasing indieclaw $(CURRENT_VERSION) → $(V)"
16
+ @# Update version in pyproject.toml
17
+ sed -i 's/^version = "$(CURRENT_VERSION)"/version = "$(V)"/' pyproject.toml
18
+ @echo " pyproject.toml updated"
19
+ @# Insert new version entry after the header in CHANGELOG.md
20
+ @DATE=$$(date +%Y-%m-%d); \
21
+ PREV_TAG=$$(git describe --tags --abbrev=0 2>/dev/null || echo ""); \
22
+ if [ -n "$$PREV_TAG" ]; then \
23
+ COMMITS=$$(git log $$PREV_TAG..HEAD --oneline --no-merges | grep -v "bump version\|Bump version"); \
24
+ else \
25
+ COMMITS=$$(git log --oneline --no-merges -20); \
26
+ fi; \
27
+ BODY=$$(echo "$$COMMITS" | sed 's/^[a-f0-9]* /- /'); \
28
+ { head -3 CHANGELOG.md; \
29
+ echo ""; \
30
+ echo "## [$(V)] - $$DATE"; \
31
+ echo ""; \
32
+ echo "$$BODY"; \
33
+ echo ""; \
34
+ tail -n +4 CHANGELOG.md; \
35
+ } > CHANGELOG.md.tmp && mv CHANGELOG.md.tmp CHANGELOG.md
36
+ @echo " CHANGELOG.md updated"
37
+ @# Lock file
38
+ uv lock 2>/dev/null || true
39
+ @# Stage, commit, tag
40
+ git add pyproject.toml CHANGELOG.md uv.lock
41
+ git commit -m "release: v$(V)"
42
+ git tag -a "v$(V)" -m "v$(V)"
43
+ @echo ""
44
+ @echo "Done. Tagged v$(V). Push with: git push && git push --tags"
@@ -0,0 +1,117 @@
1
+ Metadata-Version: 2.4
2
+ Name: indieclaw
3
+ Version: 0.1.0
4
+ Summary: Self-hosted Telegram AI agent. 10 tools, skills, subconscious, CLI learning.
5
+ Author: IndieClaw Contributors
6
+ License-File: LICENSE
7
+ Requires-Python: >=3.12
8
+ Requires-Dist: aiohttp>=3.9.0
9
+ Requires-Dist: apscheduler>=3.10.0
10
+ Requires-Dist: claude-agent-sdk>=0.1.44
11
+ Requires-Dist: edge-tts>=6.1.0
12
+ Requires-Dist: loguru>=0.7.0
13
+ Requires-Dist: playwright>=1.40.0
14
+ Requires-Dist: python-dotenv>=1.0.0
15
+ Requires-Dist: python-telegram-bot>=20.0
16
+ Requires-Dist: pyyaml>=6.0
17
+ Requires-Dist: questionary>=2.0.0
18
+ Requires-Dist: requests>=2.32.0
19
+ Requires-Dist: rich>=13.0
20
+ Requires-Dist: textual>=0.70
21
+ Requires-Dist: typer>=0.24.1
22
+ Description-Content-Type: text/markdown
23
+
24
+ # IndieClaw
25
+
26
+ [![python-doctor](https://img.shields.io/badge/python--doctor-90%2F100-brightgreen)](https://github.com/saikatkumardey/python-doctor)
27
+
28
+ Personal AI agent on Telegram. Self-hosted, powered by Claude.
29
+
30
+ ## Install
31
+
32
+ ```bash
33
+ curl -fsSL https://raw.githubusercontent.com/saikatkumardey/indieclaw/main/install.sh | bash
34
+ ```
35
+
36
+ Or manually:
37
+
38
+ ```bash
39
+ pip install uv
40
+ uv tool install git+https://github.com/saikatkumardey/indieclaw
41
+ indieclaw setup
42
+ ```
43
+
44
+ Setup asks for your Telegram bot token, user ID, and Claude auth. Get a bot token from [@BotFather](https://t.me/BotFather) and your user ID from [@userinfobot](https://t.me/userinfobot).
45
+
46
+ ## Run
47
+
48
+ ```bash
49
+ indieclaw start # background daemon
50
+ indieclaw start -f # foreground
51
+ indieclaw chat # interactive TUI (no Telegram needed)
52
+ indieclaw logs -f # stream logs
53
+ indieclaw stop
54
+ indieclaw restart
55
+ ```
56
+
57
+ `indieclaw chat` launches a terminal UI for chatting directly with your agent — useful for testing, debugging, or when you don't want to go through Telegram.
58
+
59
+ On Linux with systemd, `indieclaw setup` installs and starts the service automatically.
60
+
61
+ ## Commands
62
+
63
+ | Command | |
64
+ |---------|--|
65
+ | `/status` | Model, tools, token usage |
66
+ | `/model` | Switch Claude model |
67
+ | `/effort` | Switch thinking effort |
68
+ | `/reset` | Clear conversation history |
69
+ | `/restart` | Restart the bot |
70
+ | `/update` | Pull latest and restart |
71
+ | `/cc <prompt>` | Live Claude Code session (streaming) |
72
+
73
+ ## Workspace
74
+
75
+ Everything lives in `~/.indieclaw/`:
76
+
77
+ | File | Purpose |
78
+ |------|---------|
79
+ | `SOUL.md` | Agent identity and instructions |
80
+ | `USER.md` | Your profile (name, timezone, preferences) |
81
+ | `MEMORY.md` | Persistent memory across sessions |
82
+ | `crons.yaml` | Scheduled jobs |
83
+ | `skills/*/SKILL.md` | Skill docs injected into system prompt |
84
+ | `tools/*.py` | Custom tools — hot-loaded, no restart needed |
85
+ | `sessions/*.jsonl` | Conversation logs |
86
+ | `handover.md` | State snapshot across restarts |
87
+ | `subconscious.yaml` | Background reflection threads |
88
+
89
+ Override the workspace path: `INDIECLAW_HOME=/path/to/dir`
90
+
91
+ ## Subconscious
92
+
93
+ A background reflection loop that runs every 2 hours. The agent reviews open threads, recent conversations, and memory — then decides whether to act (send a message, spawn a task) or stay quiet.
94
+
95
+ Threads are tracked in `~/.indieclaw/subconscious.yaml`. The agent can add, resolve, or keep threads across cycles. Disable it or change the interval in `~/.indieclaw/config.yaml`:
96
+
97
+ ```yaml
98
+ subconscious_enabled: false
99
+ subconscious_interval_hours: 4
100
+ ```
101
+
102
+ ## Custom tools
103
+
104
+ Drop a `.py` file in `~/.indieclaw/tools/` with a `SCHEMA` dict and `execute()` function. Available on the next message, no restart needed.
105
+
106
+ ## Update
107
+
108
+ ```bash
109
+ indieclaw update # from terminal
110
+ /update # from Telegram
111
+ ```
112
+
113
+ Saves a handover note before restarting and picks up where it left off.
114
+
115
+ ## License
116
+
117
+ MIT
@@ -0,0 +1,94 @@
1
+ # IndieClaw
2
+
3
+ [![python-doctor](https://img.shields.io/badge/python--doctor-90%2F100-brightgreen)](https://github.com/saikatkumardey/python-doctor)
4
+
5
+ Personal AI agent on Telegram. Self-hosted, powered by Claude.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ curl -fsSL https://raw.githubusercontent.com/saikatkumardey/indieclaw/main/install.sh | bash
11
+ ```
12
+
13
+ Or manually:
14
+
15
+ ```bash
16
+ pip install uv
17
+ uv tool install git+https://github.com/saikatkumardey/indieclaw
18
+ indieclaw setup
19
+ ```
20
+
21
+ Setup asks for your Telegram bot token, user ID, and Claude auth. Get a bot token from [@BotFather](https://t.me/BotFather) and your user ID from [@userinfobot](https://t.me/userinfobot).
22
+
23
+ ## Run
24
+
25
+ ```bash
26
+ indieclaw start # background daemon
27
+ indieclaw start -f # foreground
28
+ indieclaw chat # interactive TUI (no Telegram needed)
29
+ indieclaw logs -f # stream logs
30
+ indieclaw stop
31
+ indieclaw restart
32
+ ```
33
+
34
+ `indieclaw chat` launches a terminal UI for chatting directly with your agent — useful for testing, debugging, or when you don't want to go through Telegram.
35
+
36
+ On Linux with systemd, `indieclaw setup` installs and starts the service automatically.
37
+
38
+ ## Commands
39
+
40
+ | Command | |
41
+ |---------|--|
42
+ | `/status` | Model, tools, token usage |
43
+ | `/model` | Switch Claude model |
44
+ | `/effort` | Switch thinking effort |
45
+ | `/reset` | Clear conversation history |
46
+ | `/restart` | Restart the bot |
47
+ | `/update` | Pull latest and restart |
48
+ | `/cc <prompt>` | Live Claude Code session (streaming) |
49
+
50
+ ## Workspace
51
+
52
+ Everything lives in `~/.indieclaw/`:
53
+
54
+ | File | Purpose |
55
+ |------|---------|
56
+ | `SOUL.md` | Agent identity and instructions |
57
+ | `USER.md` | Your profile (name, timezone, preferences) |
58
+ | `MEMORY.md` | Persistent memory across sessions |
59
+ | `crons.yaml` | Scheduled jobs |
60
+ | `skills/*/SKILL.md` | Skill docs injected into system prompt |
61
+ | `tools/*.py` | Custom tools — hot-loaded, no restart needed |
62
+ | `sessions/*.jsonl` | Conversation logs |
63
+ | `handover.md` | State snapshot across restarts |
64
+ | `subconscious.yaml` | Background reflection threads |
65
+
66
+ Override the workspace path: `INDIECLAW_HOME=/path/to/dir`
67
+
68
+ ## Subconscious
69
+
70
+ A background reflection loop that runs every 2 hours. The agent reviews open threads, recent conversations, and memory — then decides whether to act (send a message, spawn a task) or stay quiet.
71
+
72
+ Threads are tracked in `~/.indieclaw/subconscious.yaml`. The agent can add, resolve, or keep threads across cycles. Disable it or change the interval in `~/.indieclaw/config.yaml`:
73
+
74
+ ```yaml
75
+ subconscious_enabled: false
76
+ subconscious_interval_hours: 4
77
+ ```
78
+
79
+ ## Custom tools
80
+
81
+ Drop a `.py` file in `~/.indieclaw/tools/` with a `SCHEMA` dict and `execute()` function. Available on the next message, no restart needed.
82
+
83
+ ## Update
84
+
85
+ ```bash
86
+ indieclaw update # from terminal
87
+ /update # from Telegram
88
+ ```
89
+
90
+ Saves a handover note before restarting and picks up where it left off.
91
+
92
+ ## License
93
+
94
+ MIT
@@ -0,0 +1,13 @@
1
+ #!/bin/bash
2
+ # Deploy indieclaw: reinstall and restart service.
3
+ set -e
4
+ cd "$(dirname "$0")"
5
+ uv tool uninstall indieclaw 2>/dev/null || true
6
+ uv tool install .
7
+ if systemctl is-active --quiet indieclaw 2>/dev/null; then
8
+ systemctl restart indieclaw && echo "Service restarted."
9
+ elif systemctl cat indieclaw &>/dev/null 2>&1; then
10
+ systemctl start indieclaw && echo "Service started."
11
+ else
12
+ echo "No systemd service found. Run: indieclaw setup (to generate the service file), then: indieclaw start"
13
+ fi