Skip to content
Open
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
3 changes: 3 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
src/githubbot_core/starters/posix/*.sh text eol=lf
src/githubbot_core/starters/windows/*.bat text eol=crlf
src/githubbot_core/starters/windows/providers/*.bat text eol=crlf
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,11 @@ Format: [Keep a Changelog](https://keepachangelog.com/de/1.1.0/), [Semantic Vers
- Credential-Adapter (Umgebung, `gh auth token`) mit Schwärzung / credential adapter with redaction.
- Namensraumunabhängiges Exact-SHA-Review-Gate samt Workflow-Scaffold /
namespace-independent exact-SHA review gate with workflow scaffold.


## Unreleased

- Ship neutral MULTI-BOT Windows/POSIX starters, German prompt and runtime helpers in wheel/sdist.
- Export separate MULTI-BOT role descriptors using the strict existing schema; preserve system-agent unchanged.
- Delegate optional provider launching to TASKPLAN; missing dependency fails closed with an install hint.
- Keep roots, accounts, authentication and full-access settings in explicit private instance configuration.
28 changes: 28 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -180,3 +180,31 @@ No third-party code is included; see [THIRD_PARTY_LICENSES.md](THIRD_PARTY_LICEN
## License

[MIT](LICENSE)


## Optional MULTI-BOT role

`python -m githubbot_core multi-bot` delegates mode/provider/model/effort selection to the
optional TASKPLAN launcher. The visible menu is **1 operator** (default), **2 bot-triage** (PR triage/reviews only), and **3 github-maintain** (fixes and maintenance). Operator checks fresh PR work before every unit, then fixes, then policies/gates/privacy and care. Initial policy preference and evidenced policy/care alternation are a documented heuristic; urgent policies precede routine care. Missing TASKPLAN produces an installation hint
and starts no provider. `--dry-run` enables TASKPLAN's no-probe dry run.

Wheels and sdists ship `githubbot_core/prompts/MULTI-BOT.de.md`, neutral starters under
`githubbot_core/starters/windows` and `starters/posix`, and the care/probe helper modules.
`githubbot-core --json multi-bot-role --mode operator` exports one
role using the existing strict descriptor schema. `system-agent` remains unchanged;
role definitions live in the separate packaged `multibot_roles.json` resource. Runtime root defaults to the current directory. Merge is
disabled and full access is not forced by public defaults. Explicit `--config` layers may
set `multi_bot.root`, `instance_prompt`, `merge_account`, `merge_enabled`, and
`trusted_automation`. The configured action permission ceiling remains binding.

The starter never searches hidden credential paths. Accounts, authentication, slots and
host roots belong to private instance configuration. `multi-bot-care --root PATH next`
and `multi-bot-probe --root PATH` require explicit registry/org/host-log data and fail
closed when absent. Private runtime/extensions remain separate consumers; no background
service or executable automatic merge is installed.

Named legacy flags `triage`, `review-merge`, and `aftercare` retain their original limited behavior and are absent from the new three-choice menu. Choosing a role never enables merges or widens permissions.

`githubbot-core --json multi-bot-select --input SNAPSHOT.json --mode operator` makes a deterministic read-only decision from an existing snapshot. It creates no queue, work item, persistent state, or agent. The snapshot contains `candidates`, optional `processed` and `lastMaintenance`. Candidates require `id`, an exact lowercase 40-character commit `revision`, `status` (`ready`, `blocked`, `done`), `category` (`prs`, `fixes`, `policies`, `care`), and optional boolean `urgent`. Processed records carry the same identity/category, blocked/done status and a nonempty `evidence` reference; the caller verifies the actual evidence. `lastMaintenance` points via `{id, revision}` to an evidenced successful policy/care completion. Selection and repeated empty checks never advance it. Unknown values are rejected. Exact processed heads are skipped; changed PR heads can preempt fixes and maintenance. Equal-priority candidates sort by ID and SHA.

The neutral ASCII Windows starter is titled MULTI-BOT COMPANION, explains foreground operation and pauses after success, failure or STOP. Only explicit `--dry-run`, `TASKPLAN_STARTER_DRY_RUN=1` or `MULTIBOT_NO_PAUSE=1` skips the pause. It installs nothing and opens no extra window.
37 changes: 37 additions & 0 deletions README_de.md
Original file line number Diff line number Diff line change
Expand Up @@ -183,3 +183,40 @@ Historie aufgebaut. Es ist kein Fremdcode enthalten; siehe
## Lizenz

[MIT](LICENSE)


## MULTI-BOT als optionale Agentenrolle

`python -m githubbot_core multi-bot` startet die paketierte Rolle über TASKPLAN. Das sichtbare Menü enthält **1 operator** (Standard), **2 bot-triage** (nur PR-Triage/Reviews) und **3 github-maintain** (Fixes und Pflege). Operator prüft vor jeder neuen Einheit frisch PRs, dann konkrete Fixes, dann Policies/Gates/Privacy und Care. Die 3a/3b-Heuristik bevorzugt anfangs Policies und wechselt nach belegten Abschlüssen; dringende Policies gehen vor normaler Care. Das Startcenter verwendet denselben CLI-Aufruf.
`--provider`, `--model`, `--effort` und `--mode` wählen ausdrücklich; die Provider-Ausführung
bleibt in TASKPLAN. Fehlt dieses optionale Modul, erscheint ein Installationshinweis und
kein Anbieter startet. `--dry-run` aktiviert TASKPLANs Trockenlauf ohne Sonde.

Wheel und sdist enthalten den deutschen Prompt, neutrale Windows-/POSIX-Starter und die
Care-/Probe-Helfer. Ressourcen: `githubbot_core/prompts/MULTI-BOT.de.md`,
`githubbot_core/starters/windows/MULTI-BOT.bat`, `starters/windows/providers/`,
`starters/posix/start-multi-bot.sh`. Auf POSIX funktioniert `sh start-multi-bot.sh` auch
bei verlorenem Ausführungsrecht. Systemprofil: `githubbot-core --json multi-bot-role --mode operator`
exportiert jeweils einen Rollen-Descriptor im bestehenden strikten Schema. Der bisherige
`system-agent`-Descriptor bleibt unverändert; die drei Rollen stehen separat in der
Paketresource `multibot_roles.json`.

Standardmäßig ist der Betriebsroot das aktuelle Verzeichnis, Merge deaktiviert und
Vollzugriff nicht erzwungen. Explizite private Konfiguration: `multi_bot.root`,
`instance_prompt`, `merge_account`, `merge_enabled`, optional `trusted_automation` in
`--config DATEI`; `MULTIBOT_ROOT`/`MULTIBOT_INSTANCE_PROMPT` sind entsprechende Overrides.
Der Starter lädt keine Tokens aus einem festen Credential-Ordner. Konten, Auth, Slots und
Hostpfade gehören in die Instanz, niemals in die neutrale Vorlage. Core-Permissions können
weiterhin nur eingeschränkt werden; der Rollenprompt erweitert die Aktionsrechte nicht.

`githubbot-core multi-bot-care --root PFAD next` und `multi-bot-probe --root PFAD` lesen
explizite Instanzdaten (`config/repo_registry.json`, `config/orgs.json`, Hostlogs). Ohne
Daten melden sie HOLD. Claims ersetzen keine Projektsperren; keine ausführbare Merge-Automatik
oder neue Hintergrundroutine wird installiert. Private Extensions und private Runtime
bleiben eigenständige, getrennte Konsumenten.

Die alten benannten Flags `triage`, `review-merge`, `aftercare` bleiben mit ihrem bisherigen begrenzten Umfang verfügbar, erscheinen aber nicht im neuen Dreiermenü. Eine Rollenwahl aktiviert keine Merges und erweitert keine Permission-Decke.

`githubbot-core --json multi-bot-select --input SNAPSHOT.json --mode operator` wählt deterministisch und ausschließlich lesend aus vorhandenen Kandidaten. Keine Queue, Auftragsanlage, Persistierung oder Agentenstarts. Der Snapshot enthält `candidates`, optional `processed` und `lastMaintenance`: Kandidaten brauchen `id`, exakte 40-stellige lowercase Commit-`revision`, `status` (`ready`, `blocked`, `done`), `category` (`prs`, `fixes`, `policies`, `care`) und optional `urgent` (bool). Ein `processed`-Eintrag bindet dieselben Felder an `blocked`/`done` und eine nichtleere `evidence`-Referenz; die tatsächliche Belegprüfung liegt beim Aufrufer. `lastMaintenance` ist ein `{id, revision}`-Verweis auf einen solchen erfolgreichen Policies-/Care-Abschluss. Auswahl und zwei leere Prüfungen verändern nichts. Unbekannte Werte werden abgewiesen. Neue PR-Heads kommen wieder vor Fixes/Pflege; erledigte oder blockierte gleiche Heads bleiben übersprungen, bis der zuständige Workflow neue Belege liefert. Gleichrangige Kandidaten werden nach ID und SHA sortiert.

Der öffentliche ASCII-Windows-Starter trägt den Titel MULTI-BOT COMPANION, zeigt den Vordergrundbetrieb und wartet nach Erfolg, Fehler oder STOP auf eine Taste. Ausnahmen: explizites `--dry-run`, `TASKPLAN_STARTER_DRY_RUN=1` oder `MULTIBOT_NO_PAUSE=1`. Er installiert nichts und öffnet kein zusätzliches Fenster.
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ version = { attr = "githubbot_core.__version__" }
where = ["src"]

[tool.setuptools.package-data]
githubbot_core = ["default_config.json", "system_agent.json", "templates/*.yml"]
githubbot_core = ["default_config.json", "system_agent.json", "multibot_roles.json", "multibot.example.json", "templates/*.yml", "prompts/*.md",
"starters/windows/*.bat", "starters/windows/providers/*.bat", "starters/posix/*.sh"]

[tool.pytest.ini_options]
testpaths = ["tests"]
Expand Down
48 changes: 48 additions & 0 deletions src/githubbot_core/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,35 @@ def cmd_system_agent(args, config, transport) -> int:
return EXIT_OK


def cmd_multibot_role(args, config, transport) -> int:
"""Export one role using exactly the existing system-agent descriptor shape."""
from .multibot import choose_mode, packaged_role

mode = choose_mode(args.mode)
schema, role_id, blueprint = packaged_role(mode, package=resources.files("githubbot_core"))
data = {
"schema": schema,
"id": role_id,
"version": __version__,
"sha256": template_sha256(schema, role_id, blueprint),
"capability": {"package": "githubbot-core", "version": __version__, "spi_version": plugins.SPI_VERSION},
"blueprint": blueprint,
"permissions": config.get("permissions", {}),
}
_emit(args, "multi-bot-role", True, "read", data, [], f"MULTI-BOT role {mode} sha256 {data['sha256']}")
return EXIT_OK


def cmd_multibot_select(args, config, transport) -> int:
"""Choose from an existing offline snapshot; never enqueue, persist or execute work."""
from .multibot_select import select_work

snapshot = json.loads(Path(args.input).read_text(encoding="utf-8"))
data = select_work(snapshot, mode=args.mode)
_emit(args, "multi-bot-select", True, "read", data, [], data["reason"])
return EXIT_OK


def cmd_classify(args, config, transport) -> int:
classifier = IssueClassifier(config)
results = [classifier.classify(issue) for issue in _read_issues(Path(args.input))]
Expand Down Expand Up @@ -340,6 +369,14 @@ def build_parser() -> argparse.ArgumentParser:
sub.add_parser("system-agent", help="versioned system agent template of this package").set_defaults(
func=cmd_system_agent
)
p = sub.add_parser("multi-bot-role", help="one MULTI-BOT role as a compatible system-agent descriptor")
p.add_argument("--mode", default="operator")
p.set_defaults(func=cmd_multibot_role)

p = sub.add_parser("multi-bot-select", help="read-only deterministic selection from an existing snapshot")
p.add_argument("--input", required=True)
p.add_argument("--mode", default="operator", choices=("operator", "bot-triage", "github-maintain"))
p.set_defaults(func=cmd_multibot_select)

p = sub.add_parser("classify", help="classify issues from a JSON file (offline)")
p.add_argument("--input", required=True)
Expand Down Expand Up @@ -390,6 +427,8 @@ def add_apply_flags(p):
p.set_defaults(func=cmd_gate_scaffold)

sub.add_parser("review-gate", help="signed exact-SHA receipts (see: review-gate --help)", add_help=False)
for name in ("multi-bot", "multi-bot-care", "multi-bot-probe"):
sub.add_parser(name, help="packaged MULTI-BOT role and runtime helpers", add_help=False)
return parser


Expand All @@ -408,6 +447,15 @@ def _subcommand_index(argv: list[str]) -> Optional[int]:
def main(argv: Optional[list[str]] = None, transport=None) -> int:
argv = list(sys.argv[1:] if argv is None else argv)
index = _subcommand_index(argv)
if index is not None and argv[index] in {"multi-bot", "multi-bot-care", "multi-bot-probe"}:
from . import multibot, multibot_care, multibot_probe

entry = {
"multi-bot": multibot.main,
"multi-bot-care": multibot_care.main,
"multi-bot-probe": multibot_probe.main,
}[argv[index]]
return entry(argv[:index] + argv[index + 1 :])
if index is not None and argv[index] == "review-gate":
from . import review_gate

Expand Down
13 changes: 13 additions & 0 deletions src/githubbot_core/multibot.example.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"multi_bot": {
"merge_enabled": false,
"merge_account": "",
"trusted_automation": false,
"mode": "operator",
"provider": "",
"model": "",
"effort": "",
"root": "",
"instance_prompt": ""
}
}
Loading
Loading