Repository navigation
Releases: hassancs91/PyRun
Releases · hassancs91/PyRun
Release list
PyRun 2.0.0
Upgrade notes (from 1.x)
- Selected secret injection is now exact. A user script in Selected mode
receives only the secrets attached to it on the script form. Before 2.0 it also
received every unowned workspace secret, which is the same set All gives, so
the setting narrowed nothing. After upgrading, open each script that uses
Selected, attach the secrets it reads (Auto-detect from code finds them) or
switch it to All. Plugin scripts in Selected mode (the SDK default) get
their own plugin's secrets and the secrets attached to them; a user's unowned
secret no longer reaches them unless it is attached (the bundled example
plugins only use their own secrets). - Datastore and plugin API tokens are stored hashed. Like Unified API
tokens, they are kept only as a SHA-256 digest; the upgrade (migration 0065)
hashes the existing ones. Tokens keep working unchanged; the list shows the
first 8 and last 4 characters. A database copy or dump no longer contains
usable tokens. Rolling back to 1.x after upgrading invalidates them (create
new ones there). - Each script has its own working folder. A run's current directory is now
/app/data/workdir/<script id>/(the id is in the script's URL) instead of the
folder every script shared. Files a run writes there are there for the script's
next run, other scripts no longer see them, and the folder is deleted with the
script (a backup restore keeps the folders of the scripts it restores; the files
are not part of backups). Files scripts wrote before 2.0 stay in
/app/data/workdir/; move what a script still reads into its own folder, or
read it by absolute path. - Container process limit.
docker-compose.coolify.ymlnow sets
pids_limit: 2048(processes and threads for the whole container). Scripts
run as root in the image and the kernel exempts root from the per-run process
limit (RLIMIT_NPROC), so that setting can't stop a fork bomb; Settings →
Isolation now marks it "not enforced while scripts run as root". Raise the
limit if your scripts start many processes (several headless browsers), and set
one yourself on other deployments (docker run --pids-limit, or compose
pids_limit). - New image name, and Coolify keeps your old compose file. New releases are
published ashasanaboulhasan/pyrun; an install that still pulls
hasanaboulhasan/pyrunner:lateststays on the last image published under that
name, so change the image name when you update. On Coolify, Redeploy pulls
the image named in the compose file the resource already has: a 1.x Docker
Compose resource keeps the 1.x compose, withoutpids_limit: 2048,
RATELIMIT_TRUSTED_PROXY_DEPTH=1(login lockout and per-IP rate limits then
see Traefik's address for every visitor) or the pass-through for
DATABASE_URL,PYRUNNER_DATA_DB_URLandPYRUNNER_ALLOW_PRIVATE_NETWORK.
Replace the resource's compose with the 2.0docker-compose.coolify.yml
(keep your environment values) before you redeploy. A Docker Image resource
needs the new image name andRATELIMIT_TRUSTED_PROXY_DEPTH=1added by hand.
The Coolify install guide's Upgrading from 1.x section has the steps. - An upgraded instance keeps the name "PyRunner". 1.x saved its default
instance name in the database, and the upgrade doesn't change a saved name, so
the header, page titles and emails still say "PyRunner". Change it under
Settings → General → Instance name if you want "PyRun".
Added
- Workspace Brains — immutable revisions and deduplicated text blobs,
a file browser with visibility and freshness badges, owner/admin edits,
revision diffs, access grants, template creation, and ZIP or public GitHub
import/export. Existing BrainOutside 1.0 content is preserved. Backup format
1.13.0 includes opted-in brains and their full history; token grants must be
recreated after restore. - Brain read and write tools — shared REST/MCP, signed script loopback,
pluginBrainAPI(SDK 2.7) and grant-filtered agent tools. Captures produce
validated proposals for owner/admin review, with diffs, conflict re-review,
idempotent approval and cost caps. The confined reader assembles cited context;
console requests run asynchronously. Optional vector search verifies results
against canonical notes and the caller's current tier. - GitHub Brain sync — HTTP Git Data exports with explicit all-tier consent,
a reviewed initial SHA and non-force updates. Pulls create reviewable proposals;
optional polling never approves or exports. Credentials use workspace Secrets.
Restore pauses polling and drops transient jobs while preserving history. - MCP and Connect — stateless Streamable HTTP at
/mcp, shared API
handlers, permission-filtered OpenAPI, and workspace connector instructions.
Expiring read-only URL tokens are opt-in. Supports current per-request
protocol metadata and older clients' initialization handshake; no sessions
or streaming worker connections. - Unified API registry and REST — permission-scoped, hashed API tokens;
one schema and handler per tool-call endpoint, GET for reads, a filtered
/api/v1/_catalog, and/api/v1/_health. Existing datastore and plugin token
scopes retain their reach. Brain endpoints share these handlers; REST names
use dots (brain.get-note), MCP names hyphens (brain-get-note). - Vectors: embedding providers, vector stores and collections — Services
gains two cards: Embedding Providers
(OpenAI, Voyage, Jina, Z.AI, a local Ollama, or any OpenAI-compatible
/v1/embeddingsendpoint; Test records the vector dimension) and Vector
Stores: the built-in Local store (one SQLite file per collection on the
data volume, searched exactly with numpy), seeded and set as the default, and
Qdrant servers, where each collection becomes one Qdrant collection named
after its workspace. A new Vectors page per workspace creates collections,
pins the provider's model and vector dimension to each one, runs real searches
with JSON payload filters, browses points and deletes with a typed
confirmation.- Scripts use the new
pyrunner_vectorshelper (standard library only,
no keys in the run):get_collection("docs")thenadd_texts,
add_vectors,search,search_vector,get,count,scroll,
deleteandembed. A plugin's collections are open to that plugin's
scripts only; every other collection to any script in its workspace. Each
run is braked at 2 000 embedding calls, 20 MB of embedded text and 200 000
points written or deleted, so a runaway loop can't run up a provider bill. - Plugins get
VectorAPI(plugin SDK 2.7):provision("docs", embedding_provider=..., dimension=..., metric=...)is idempotent and
refuses to silently change a collection's model or dimension;get,
list,deleteand the same operations as the helper. Manifests declare
provisions.vector_collections, and the plugin doctor checks it. The SDK
Showcase example gains a Vectors card. - One filter grammar on both stores — equality,
$in, ranges,
$prefix,must/must_not— with strict types, array fields that match
on any element, and scores that are always "higher is better", so a
collection answers the same on Local and on Qdrant. - Native Qdrant access stays off unless the operator ticks Share
credentials with runs on the connection; then a script's
credentials()returns the URL, API key and physical collection name for
qdrant-client. - Backup format 1.13.0 carries providers and connections (upserted by name,
credentials encrypted as stored) and Local collections with their points
inline, up toPYRUNNER_VECTOR_BACKUP_MAX_MB(default 50) each; Qdrant
collections are carried as settings and reattach to the server on restore.
Removing a plugin with remove data deletes the collections it owns.
- Scripts use the new
- Cron expression schedules — a sixth run mode that takes a standard
5-field cron expression (0 9 * * 1-5for weekday mornings,*/15 9-17 * * *
for every quarter hour during business hours), for anything the guided
daily/weekly/monthly modes can't say. The form validates as you type and
previews the next three runs; the plugin SDK getsScheduleAPI.sync(..., mode="cron", cron="..."). Like the other clock-based modes the expression
is written in the schedule's timezone and converted to UTC for the
scheduler (day-of-week/month fields move with a midnight crossing, and the
daily DST resync covers cron too), so0 9 * * 1-5inAsia/Tokyoreally
fires at 09:00 Tokyo time. Contributed by @cmcau (#5); timezone conversion
added on merge. Backup format 1.8.0 carries the new field. - Yearly schedules — a run mode for "once a year on this date": pick a
month, day, time and timezone. The scheduler stores the next real local
occurrence (so the right DST offset applies for that date and a schedule
set late in December can land in the next UTC year), and 29 February runs
only in leap years — including when the timezone conversion pushes the UTC
date onto 28 February or 1 March. Available to plugins via
ScheduleAPI.sync(..., mode="yearly", month=, day=, time_str=, tz=)and
carried by backups (format 1.8.0). Contributed by @djpfs (#16). - Account management from the command line —
python manage.py useris
the way back in when the console can't help: no email configured for reset
links, a login lockout, or no admin who can sign in.
user reset-password <email>sets a new password (prompted, or--generate
to print a random one), signs out that account's sessions and clears its
lockout.user create <email> [--admin],user promote,user demote,
user unlockanduser listcover the rest; the last admin can't be
demoted. In Docker:
`docker exec -it pyrunner python manage.py us...