Skip to main content

Agent + Skill Store

A local AI agent with a headless browser, sandboxed shell, chat GUI, and a plug-and-play skill system backed by a hosted skill registry.

Python License Platform


What this is

Two programs on your machine, plus a registry server that's already hosted for you.

File Runs on Job
agent.py your machine The agent. Chat GUI, headless browser, sandboxed shell, tool loop, skill toggles.
skill-manager.py your machine App-store GUI. Sign in, browse, install, publish skills.
skill-server.py a server (hosted for you) Registry + state sync. GPL-3.0.

Skills are folders under skills/. Drop one in, restart the agent, its tools appear in the LLM's tool list. No changes to agent.py required.


About the server

You don't need to run the server yourself. A live instance is already hosted and configured:

https://skills-manager.freesrv.com

Both agent.py and skill-manager.py point at it by default. The manager tries the HTTPS domain first and automatically falls back to a raw IP (http://78.154.103.43:9074) if the domain goes down.

If you'd rather run your own, the source is included under GPL-3.0 (see License). You can fork it, self-host it, extend the endpoints, or replace the storage backend. See self-hosting the server.

The agent never auto-installs skills. You do that explicitly through the manager.


Features

  • Headless Chromium via DrissionPage — no popup window, real JS rendering
  • Sandboxed shell — allowlist + workspace jail, no pipes or metachars
  • Plug-and-play skills — each is a folder with skill.py + skill.md
  • Skill registry — publish, browse, install (hosted, or self-host)
  • Stop / Continue buttons — halt a run mid-turn, resume from last tool result
  • Local chat save — chats/current.json, auto-saved every turn
  • Cloud sync — optional, via the same registry (HTTPS + IP fallback)
  • Multi-key LLM — rotate OpenAI-compatible API keys transparently
  • Custom base URL — OpenAI, Together, Groq, DeepSeek, local vLLM, anything OpenAI-shaped
  • Dark tkinter GUI — Settings, Skills, Help dialogs, plus skill-loaded /commands
  • Two-pane Help — every skill gets its own help page, loaded from its skill.md

Bundled default skills: filesystem, public_api, temp_mail.


Quick start

1. Install dependencies

pip install DrissionPage openai

Windows: install WebView2 Runtime if the browser self-test fails. Linux: sudo apt install python3-tk.

2. Configure

Create agent_config.json:

{
  "openai_api_keys": ["sk-your-key-here"],
  "openai_base_url": "https://api.openai.com/v1",
  "openai_model": "gpt-4o",
  "cloud_sync": false
}

Or edit it from the GUI later via Settings.

3. Run

python agent.py

Or on Windows, double-click run.bat.

4. Talk to it

go to news.ycombinator.com and list the top 5 story titles
find a free API for cat facts and call it
create a snake game in a single HTML file

The skill system

A skill is a folder:

skills/my_skill/
├── skill.py     ← code
└── skill.md     ← metadata + docs

skill.py exports three things:

SKILL = {"name": "my_skill", "description": "What this does."}

def greet(name: str = "world") -> str:
    return f"Hello, {name}!"

TOOL_SCHEMAS = [{
    "type": "function",
    "function": {
        "name": "greet",
        "description": "Return a greeting.",
        "parameters": {
            "type": "object",
            "properties": {"name": {"type": "string"}},
        },
    },
}]

TOOL_CALLABLES = {"greet": greet}

That's it. Restart the agent, the LLM can call greet().

Optional COMMANDS export adds user-facing slash commands:

def _handle_ping(args: list, log) -> None:
    log(f"pong {' '.join(args)}", "dim")

COMMANDS = {
    "ping": {"handler": _handle_ping, "description": "Reply pong"},
}

Optional skill.md frontmatter gives the skill a name, version, and author. Anything after the closing --- becomes the skill's help page, visible in the Help dialog when the user clicks the skill.

Full developer guide: docs/skills.html — open in any browser.


Skill registry

Use the hosted server (default)

No setup needed. Both clients already point at https://skills-manager.freesrv.com. Just:

# Register a nickname (password is prompted)
python skill-manager.py register yourname

# Or launch the GUI
python skill-manager.py

The GUI lets you:

  • Browse the store with search
  • Install skills into ./skills/
  • Publish a folder as a skill
  • See your published skills and download counts
  • Delete skills you own

Self-hosting the server

Only needed if you want your own instance or to modify it. The server is ~450 lines of stdlib Python — no framework, no external dependencies.

Deploy:

mkdir -p /opt/skill-server && cd /opt/skill-server
# copy skill-server.py here
python3 skill-server.py --host 0.0.0.0 --port 8000

It creates skill_server.db (SQLite) and skill_storage/ on first run.

Put TLS in front with Caddy:

skills.example.com {
    reverse_proxy 127.0.0.1:8000
}

Or nginx:

server {
    listen 443 ssl;
    server_name skills.example.com;

    location /login {
        limit_req zone=login burst=3 nodelay;
        proxy_pass http://127.0.0.1:8000;
    }
    location / {
        proxy_pass http://127.0.0.1:8000;
    }
}

Point the clients at it by editing the constants at the top of both files:

SKILL_SERVER_PRIMARY  = "https://skills.example.com"
SKILL_SERVER_FALLBACK = "http://1.2.3.4:8000"

Architecture

[agent.py]                        [skill-manager.py]
     │                                     │
     │  reads token from                   │  signs in, gets token
     │  ~/.skill-manager.json              │
     │                                     │
     └──────── HTTP/HTTPS ─────────────────┘
                      │
                      ▼
       https://skills-manager.freesrv.com    (primary, hosted)
       http://78.154.103.43:9074             (fallback IP)
                      │
                      ▼
              [skill-server.py]  (already deployed)
              - /register /login /logout
              - /me
              - /skills  GET / POST / DELETE
              - /skills/<name>/download
              - /state   GET / POST

You can swap the server URL in both clients at any time.


Command reference

Agent (in the chat box)

Command What it does
/reset Clear conversation memory
/history Print recent messages
/skills List loaded + disabled skills + available commands
/save Force save chat locally and to cloud
/open <file> Open a file from the workspace
Skill commands Whatever skills register, e.g. /email, /providers

Agent buttons

Button Action
Stop Halt the running agent loop
Continue Resume from the last tool result
Send Start a new task
Save Save chat (local + cloud if enabled)
Settings Edit API keys, base URL, model, cloud sync
Skills Toggle installed skills on/off
Help Two-pane help: sections + per-skill pages

Skill manager

Command What it does
register <nick> Create an account
login <nick> Sign in
logout Sign out
whoami Show your account + published skills
list [--search Q] Browse the store
show <name> Full metadata for one skill
install <name> [--force] Download + extract to ./skills/
uninstall <name> Remove from ./skills/
installed List locally installed skills
publish <path> --name N --description D [--version V] Package and upload a folder

Configuration reference

agent_config.json

{
  "openai_api_keys": ["sk-...", "sk-..."],
  "openai_base_url": "https://api.openai.com/v1",
  "openai_model": "gpt-4o",
  "cloud_sync": false,
  "disabled_skills": [],
  "email_api": {
    "provider": "resend",
    "api_key": "re_...",
    "from_addr": "onboarding@resend.dev",
    "from_name": "Agent"
  }
}
Field Notes
openai_api_keys Multiple keys rotate per request
openai_base_url Any OpenAI-compatible endpoint
openai_model Depends on the provider
cloud_sync Sync chats/current.json to the registry
disabled_skills List of skill folder names to skip
email_api Optional, used by the temp_mail skill

~/.skill-manager.json

Managed automatically by skill-manager.py. Contains the auth token and cached skill list. Never commit this.


Security

The agent executes LLM-generated commands. That's the point, but it means you need to be careful.

Already sandboxed:

  • Shell — allowlist of commands, shell=False, CWD=workspace/, no pipes / redirects / ; / & / &&, no absolute paths outside the workspace
  • Filesystem skill — every path resolved and validated against workspace/
  • Browser — headless, in a throwaway profile
  • Server — PBKDF2 password hashing, session tokens, ownership checks on publish/delete, ZIP entry validation, upload size cap

Not sandboxed:

  • python is in the shell allowlist — the agent can read arbitrary files. If that matters, remove python, python3, node from ALLOWED_CMDS.
  • curl / wget are allowed — the agent can POST local data to remote servers. Remove them if that's a concern.
  • Skills are arbitrary Python — installing a skill is trusting its author.
  • Prompt injection via web content — a malicious page can steer the agent. Mitigated by the sandbox, not eliminated.

For untrusted use, run the whole thing in Docker.


Files at a glance

man-code/
├── agent.py                 ← the agent
├── skill-manager.py         ← the client
├── agent_config.json        ← your keys (gitignored)
├── agent_config.example.json
├── run.bat                  ← Windows launcher for the agent
├── store.bat                ← Windows launcher for the manager
├── README.md
├── LICENSE                  ← MIT (client code)
├── LICENSE-GPL              ← GPL-3.0 (server code)
├── .gitignore
├── docs/
│   └── skills.html          ← developer guide for writing skills
├── chats/
│   └── current.json         ← auto-saved conversation (gitignored)
├── skills/
│   ├── loader.py            ← loads every enabled skill
│   ├── filesystem/
│   ├── public_api/
│   └── temp_mail/
└── workspace/               ← agent's sandbox (gitignored)

skill-server.py is not in this tree. It lives on the server and is maintained separately.


Troubleshooting

Symptom Fix
browser: FAILED Install WebView2 (Windows) or check Chromium.
LLM ERROR: 401 Wrong API key, or quotes around the value.
LLM ERROR: 404 Model name doesn't match the provider.
BLOCKED: '<cmd>' not allowed Add the command to ALLOWED_CMDS in agent.py.
NOT_FOUND: <selector> CSS selector didn't match. Run browser_snapshot.
[loader] FAILED to load skill Run python skills/<name>/skill.py to see the error.
Registry times out Fallback IP should kick in; check console for [fallback].
Cloudflare blocked Add a WAF skip rule for the API paths on your server.

License

This project uses a split license:

Component License
agent.py, skill-manager.py, skills/**, docs/**, *.bat MIT — see LICENSE
skill-server.py GPL-3.0 — see LICENSE-GPL

Why the split? The client code is meant to be embedded, forked, and redistributed freely. The server is meant to stay open — if you host a modified version, you must publish your changes.

Default skills use third-party services:

  • mail.tm — receive-only temp inbox, no signup
  • Guerrilla Mail — fallback inbox
  • Resend / Brevo / Mailjet — email sending, free tiers
  • public-api-lists — public API catalog (MIT)
  • DrissionPage — browser automation (BSD-3)
  • OpenAI Python SDK — LLM client (Apache-2.0)

Metadata

Release files for agent-code 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for agent-code 1.0.0
File Size Uploaded
agent_code-1.0.0.tar.gz 62.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for agent-code 1.0.0
File Interpreter ABI Platform
agent_code-1.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 124.2 kB

Release files / agent_code-1.0.0.tar.gz

Download URL agent_code-1.0.0.tar.gz
Size 62.7 kB
Tags Source
SHA-256 checksum
How to use checksums
9dff2c0ba0b76bea31d0aa0e3b1bfa05ba113ada9fca5c5536b3f0165f1b2211
BLAKE2b-256 checksum
How to use checksums
d01e7aca31f8980eecd9d7c0c7ee3fe27003230e92254fb46cf619e5e6aa5721
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.9

Release files / agent_code-1.0.0-py3-none-any.whl

Download URL agent_code-1.0.0-py3-none-any.whl
Size 61.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
064317f4f2c7ab98f4479d3e40781ac0dcbf4a5f2fb6e22e67713f381f3b3343
BLAKE2b-256 checksum
How to use checksums
65904e94eec5378c15c14777a08dac874a2fdf8811f4861eabbe0d4b5bf04f77
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.9

Release history Release notifications | RSS feed

1.0.3

2 release files

1.0.2

2 release files

1.0.1

2 release files

This release

1.0.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page