@gapi/gcli 1.8.239 → 1.8.241
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.
- package/.agents/skills/cluster-targeting/SKILL.md +23 -0
- package/.agents/skills/local-ai-runners/SKILL.md +6 -0
- package/README-CLI.md +240 -57
- package/README.md +148 -11
- package/docs/changelog.d/2026-10-11-local-ai-runners-run-the-runner-as-a-systemd-user-service.md +36 -0
- package/docs/changelog.d/2026-10-19-dedicated-platform-cluster-cluster-scaling-topology-load-balancer-and-health-commands-c.md +31 -0
- package/docs/changelog.d/2026-10-19-lambforge-agent-skill-readme-points-to-the-lambforge-agent-skill-gcli-mcp-start-fo.md +17 -0
- package/docs/changelog.d/2026-10-19-repo-cron-create-honours-cron-triggername-readme-brought-up-to-da.md +21 -0
- package/docs/features/README.md +2 -0
- package/docs/features/dedicated-platform-cluster.md +70 -0
- package/docs/features/lambforge-agent-skill.md +22 -0
- package/docs/features/local-ai-runners.md +11 -0
- package/package.json +1 -1
- package/release/index.js +2351 -988
|
@@ -68,3 +68,26 @@ shared with or generated from gql-fission's copy.
|
|
|
68
68
|
`jest.config.js` has no `moduleNameMapper` for the `~/` tsconfig path alias
|
|
69
69
|
— new test files must use relative imports (e.g. `'../src/helpers'`), not
|
|
70
70
|
`'~/helpers'`, or the test silently fails to resolve the module.
|
|
71
|
+
|
|
72
|
+
## Managing a private cluster itself (scaling, topology, autoscale)
|
|
73
|
+
|
|
74
|
+
The `cluster:*` commands that change or watch ONE cluster
|
|
75
|
+
(`status`, `health`, `scale-events`, `cost`, `scale`,
|
|
76
|
+
`scale:control-planes`, `multi-node`, `single-node`, `autoscale`,
|
|
77
|
+
`load-balancer`) share `commands/cluster/helpers/cluster-change.ts`:
|
|
78
|
+
`resolveClusterTarget` (`--cluster <id>` or `--clusterName <name>`,
|
|
79
|
+
required), `parseIntOption`, and `runClusterChange` (mutate → print →
|
|
80
|
+
`--wait` via `pollUntilReady`; ending in `error` exits non-zero). Their
|
|
81
|
+
selections and types live in `commands/cluster/types.ts` (newer than the
|
|
82
|
+
hand-kept `@introspection`).
|
|
83
|
+
|
|
84
|
+
`cluster:apply` is the declarative path: the `cluster:` section of
|
|
85
|
+
lambforge.yaml (`ClusterDesired` in `helpers/plan.ts`, also the type of
|
|
86
|
+
`load-spec.ts`'s `cluster`). Keep `planClusterChanges` pure and ordered
|
|
87
|
+
(create | topology → workers → control planes → load balancer →
|
|
88
|
+
autoscale): each step is one background job and the cluster must be
|
|
89
|
+
`ready` before the next. A new cluster setting = a key in `ClusterDesired`,
|
|
90
|
+
a check in `validateDesired`, a step in the plan, a test in
|
|
91
|
+
`test/cluster-apply.spec.ts`, and the README "Declarative clusters" block.
|
|
92
|
+
The server merges partial autoscale input into the stored policy, so the
|
|
93
|
+
plan sends only changed keys.
|
|
@@ -23,6 +23,12 @@ security, symptom table): `graphql-server/docs/features/local-ai-runners.md`.
|
|
|
23
23
|
- Socket close aborts every in-flight Ollama request; a refused token is
|
|
24
24
|
fatal (`RunnerAuthError`), everything else reconnects with backoff.
|
|
25
25
|
- Global `WebSocket` -> Node >= 22.
|
|
26
|
+
- Daemon (`runner:daemon:*`, `daemon.ts`): systemd USER unit; never put the
|
|
27
|
+
token or other secrets in the unit (it's world-readable-ish config) - it
|
|
28
|
+
runs `runner:start`, which reads the 0600 `runner.json`. Keep exit code 78
|
|
29
|
+
for "token refused" in sync with `RestartPreventExitStatus`. Tests must
|
|
30
|
+
pass an explicit home dir to `SystemdUserService` (os.homedir() ignored a
|
|
31
|
+
changed HOME under jest and wrote into the real `~/.config` once).
|
|
26
32
|
|
|
27
33
|
## Run it against a dev stack
|
|
28
34
|
|
package/README-CLI.md
CHANGED
|
@@ -1,68 +1,65 @@
|
|
|
1
1
|
Usage: gcli [options] [command]
|
|
2
2
|
|
|
3
3
|
Options:
|
|
4
|
-
-V, --version
|
|
5
|
-
-h, --help
|
|
4
|
+
-V, --version output the version number
|
|
5
|
+
-h, --help display help for command
|
|
6
6
|
|
|
7
7
|
Commands:
|
|
8
|
-
login [options]
|
|
9
|
-
lambda:list [options]
|
|
10
|
-
lambda:get [options]
|
|
8
|
+
login [options] Login to graphql-server
|
|
9
|
+
lambda:list [options] List of all lambdas for project
|
|
10
|
+
lambda:get [options] Get lambda by id
|
|
11
11
|
lambda:create [options]
|
|
12
12
|
lambda:update [options]
|
|
13
|
-
lambda:delete [options]
|
|
14
|
-
lambda:log [options]
|
|
15
|
-
lambda:build:log [options]
|
|
16
|
-
lambda:test [options]
|
|
13
|
+
lambda:delete [options] Get lambda by id
|
|
14
|
+
lambda:log [options] Get lambda log
|
|
15
|
+
lambda:build:log [options] Get build log
|
|
16
|
+
lambda:test [options] Test lambda
|
|
17
17
|
lambda:package [options]
|
|
18
|
-
project:list
|
|
19
|
-
project:use <project>
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
environment:
|
|
26
|
-
environment:
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
cluster:
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
cluster:
|
|
40
|
-
|
|
41
|
-
cluster:
|
|
42
|
-
|
|
43
|
-
cluster:
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
rabbitmq:
|
|
48
|
-
rabbitmq:
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
plugin:installed [options]
|
|
52
|
-
|
|
53
|
-
plugin:
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
runner:
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
runner:
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
chat model picker (no flags: list them)
|
|
64
|
-
runner:delete [options] Delete a local AI runner and revoke its token
|
|
65
|
-
help [command] display help for command
|
|
18
|
+
project:list List of all projects
|
|
19
|
+
project:use <project> Adds default project to be used all around the CLI
|
|
20
|
+
project:clear Clears default project to be used all around the CLI
|
|
21
|
+
build [options] Build bundle using esbuild https://esbuild.github.io
|
|
22
|
+
environment:list [options] List of all environments for project
|
|
23
|
+
environment:create [options] Create environment for project
|
|
24
|
+
environment:update [options] Update environment for project
|
|
25
|
+
environment:delete [options] Delete environment for project
|
|
26
|
+
environment:get [options] Get environment for project
|
|
27
|
+
mcp:start [options] Start mcp proxy server
|
|
28
|
+
start [options] Start bundle using esbuild https://esbuild.github.io
|
|
29
|
+
cron:create [options] Create cron
|
|
30
|
+
cron:delete [options] Delete cron
|
|
31
|
+
cron:list [options] List of all cron jobs for project
|
|
32
|
+
cluster:create [options] Provision a private Talos cluster for a project (runs in the background - takes several minutes; use --wait to block)
|
|
33
|
+
cluster:apply [options] Make a private cluster match the `cluster:` section of lambforge.yaml: creates it if missing, then applies topology, workers, control planes, load balancer and autoscaling
|
|
34
|
+
cluster:list [options] List every private cluster this project has (it may have several - dev/stage/prod, ...)
|
|
35
|
+
cluster:teardown [options] Tear down one of a project's clusters (runs in the background - use --wait to block)
|
|
36
|
+
cluster:kubeconfig [options] Print (or save) a cluster's raw kubeconfig YAML - only available once it's 'ready'
|
|
37
|
+
cluster:status [options] Every cluster's status, agent, nodes, CPU/memory load, autoscaling and open issues (or one with --cluster)
|
|
38
|
+
cluster:health [options] The latest health report of a cluster's agent, with every node
|
|
39
|
+
cluster:scale-events [options] Manual and autoscaler scale history, newest first
|
|
40
|
+
cluster:cost [options] Month-to-date cost and the monthly estimate of the project's private clusters
|
|
41
|
+
cluster:scale [options] Set the number of worker nodes (1-10) of a multi-node cluster - billed per node-hour
|
|
42
|
+
cluster:scale:control-planes [options] Set the number of control-plane nodes (1, 3 or 5)
|
|
43
|
+
cluster:autoscale [options] Change the worker autoscaling policy - only the flags you pass change
|
|
44
|
+
cluster:multi-node [options] Convert a single-node cluster to dedicated worker nodes (required for autoscaling)
|
|
45
|
+
cluster:single-node [options] Convert a multi-node cluster back to a single node (removes the worker nodes)
|
|
46
|
+
cluster:load-balancer [options] Add or remove the cluster's load balancer (billed per hour while enabled)
|
|
47
|
+
rabbitmq:create [options] Provision a RabbitMQ broker for a project (a project may have several)
|
|
48
|
+
rabbitmq:list [options] List every RabbitMQ broker for a project
|
|
49
|
+
rabbitmq:delete [options] Delete a RabbitMQ broker
|
|
50
|
+
plugin:list List every plugin available in the marketplace catalog
|
|
51
|
+
plugin:installed [options] List plugins installed for a project (may include the same plugin on several clusters)
|
|
52
|
+
plugin:install [options] Install a marketplace plugin for a project
|
|
53
|
+
plugin:uninstall [options] Uninstall a plugin from a project (--cluster picks which installation, if it's on several)
|
|
54
|
+
runner:start [options] Connect this machine's Ollama to the Lambforge chat as a local AI runner (outbound connection only - works behind NAT, Ollama is never exposed)
|
|
55
|
+
runner:daemon:install|runner:start:daemon [options] Run the runner in the background as a systemd user service: starts with your session, restarts on failure (Linux)
|
|
56
|
+
runner:daemon:status [options] Show the runner service status (systemctl --user status)
|
|
57
|
+
runner:daemon:logs [options] Follow the runner service log (journalctl --user -f)
|
|
58
|
+
runner:daemon:uninstall [options] Stop and remove the runner service (the runner stays registered)
|
|
59
|
+
runner:list List your local AI runners and the models they serve
|
|
60
|
+
runner:models [options] Choose which of a runner's models appear in the chat model picker (no flags: list them)
|
|
61
|
+
runner:delete [options] Delete a local AI runner and revoke its token
|
|
62
|
+
help [command] display help for command
|
|
66
63
|
[36m
|
|
67
64
|
--- Subcommand: login ---[0m
|
|
68
65
|
Usage: gcli login [options]
|
|
@@ -522,6 +519,19 @@ Options:
|
|
|
522
519
|
--wait Block until the cluster is ready (or errors)
|
|
523
520
|
-h, --help display help for command
|
|
524
521
|
[36m
|
|
522
|
+
--- Subcommand: cluster:apply ---[0m
|
|
523
|
+
Usage: gcli cluster:apply [options]
|
|
524
|
+
|
|
525
|
+
Make a private cluster match the `cluster:` section of lambforge.yaml: creates it if missing, then applies topology, workers, control planes, load balancer and autoscaling
|
|
526
|
+
|
|
527
|
+
Options:
|
|
528
|
+
-p, --project <project>
|
|
529
|
+
-spec, --spec <spec> Spec file (default: lambforge.yaml / cluster.yaml)
|
|
530
|
+
--dry-run Print the plan, change nothing
|
|
531
|
+
--yes Also apply steps that remove capacity or the load
|
|
532
|
+
balancer IP
|
|
533
|
+
-h, --help display help for command
|
|
534
|
+
[36m
|
|
525
535
|
--- Subcommand: cluster:list ---[0m
|
|
526
536
|
Usage: gcli cluster:list [options]
|
|
527
537
|
|
|
@@ -553,6 +563,135 @@ Options:
|
|
|
553
563
|
-o, --output <output> Write to this file instead of stdout
|
|
554
564
|
-h, --help display help for command
|
|
555
565
|
[36m
|
|
566
|
+
--- Subcommand: cluster:status ---[0m
|
|
567
|
+
Usage: gcli cluster:status [options]
|
|
568
|
+
|
|
569
|
+
Every cluster's status, agent, nodes, CPU/memory load, autoscaling and open issues (or one with --cluster)
|
|
570
|
+
|
|
571
|
+
Options:
|
|
572
|
+
-p, --project <project>
|
|
573
|
+
-c, --cluster <cluster> Cluster id (see cluster:list)
|
|
574
|
+
--clusterName <clusterName> Cluster name instead of --cluster
|
|
575
|
+
-h, --help display help for command
|
|
576
|
+
[36m
|
|
577
|
+
--- Subcommand: cluster:health ---[0m
|
|
578
|
+
Usage: gcli cluster:health [options]
|
|
579
|
+
|
|
580
|
+
The latest health report of a cluster's agent, with every node
|
|
581
|
+
|
|
582
|
+
Options:
|
|
583
|
+
-p, --project <project>
|
|
584
|
+
-c, --cluster <cluster> Cluster id (see cluster:list)
|
|
585
|
+
--clusterName <clusterName> Cluster name instead of --cluster
|
|
586
|
+
-h, --help display help for command
|
|
587
|
+
[36m
|
|
588
|
+
--- Subcommand: cluster:scale-events ---[0m
|
|
589
|
+
Usage: gcli cluster:scale-events [options]
|
|
590
|
+
|
|
591
|
+
Manual and autoscaler scale history, newest first
|
|
592
|
+
|
|
593
|
+
Options:
|
|
594
|
+
-p, --project <project>
|
|
595
|
+
-c, --cluster <cluster> Cluster id (see cluster:list)
|
|
596
|
+
--clusterName <clusterName> Cluster name instead of --cluster
|
|
597
|
+
--limit <limit> How many events (default 20)
|
|
598
|
+
-h, --help display help for command
|
|
599
|
+
[36m
|
|
600
|
+
--- Subcommand: cluster:cost ---[0m
|
|
601
|
+
Usage: gcli cluster:cost [options]
|
|
602
|
+
|
|
603
|
+
Month-to-date cost and the monthly estimate of the project's private clusters
|
|
604
|
+
|
|
605
|
+
Options:
|
|
606
|
+
-p, --project <project>
|
|
607
|
+
-h, --help display help for command
|
|
608
|
+
[36m
|
|
609
|
+
--- Subcommand: cluster:scale ---[0m
|
|
610
|
+
Usage: gcli cluster:scale [options]
|
|
611
|
+
|
|
612
|
+
Set the number of worker nodes (1-10) of a multi-node cluster - billed per node-hour
|
|
613
|
+
|
|
614
|
+
Options:
|
|
615
|
+
-p, --project <project>
|
|
616
|
+
-c, --cluster <cluster> Cluster id (see cluster:list)
|
|
617
|
+
--clusterName <clusterName> Cluster name instead of --cluster
|
|
618
|
+
--workers <workers> Worker nodes, 1-10
|
|
619
|
+
--wait Block until the cluster settles
|
|
620
|
+
-h, --help display help for command
|
|
621
|
+
[36m
|
|
622
|
+
--- Subcommand: cluster:scale:control-planes ---[0m
|
|
623
|
+
Usage: gcli cluster:scale:control-planes [options]
|
|
624
|
+
|
|
625
|
+
Set the number of control-plane nodes (1, 3 or 5)
|
|
626
|
+
|
|
627
|
+
Options:
|
|
628
|
+
-p, --project <project>
|
|
629
|
+
-c, --cluster <cluster> Cluster id (see cluster:list)
|
|
630
|
+
--clusterName <clusterName> Cluster name instead of --cluster
|
|
631
|
+
--count <count> Control planes: 1, 3 or 5
|
|
632
|
+
--wait Block until the cluster settles
|
|
633
|
+
-h, --help display help for command
|
|
634
|
+
[36m
|
|
635
|
+
--- Subcommand: cluster:autoscale ---[0m
|
|
636
|
+
Usage: gcli cluster:autoscale [options]
|
|
637
|
+
|
|
638
|
+
Change the worker autoscaling policy - only the flags you pass change
|
|
639
|
+
|
|
640
|
+
Options:
|
|
641
|
+
-p, --project <project>
|
|
642
|
+
-c, --cluster <cluster> Cluster id (see cluster:list)
|
|
643
|
+
--clusterName <clusterName> Cluster name instead of --cluster
|
|
644
|
+
--enable Turn autoscaling on (multi-node clusters only)
|
|
645
|
+
--disable Turn autoscaling off
|
|
646
|
+
--min <min> Minimum workers (1-10)
|
|
647
|
+
--max <max> Maximum workers (1-10)
|
|
648
|
+
--cpuUp <percent> Scale up at this CPU % (1-100)
|
|
649
|
+
--memUp <percent> Scale up at this memory % (1-100)
|
|
650
|
+
--cpuDown <percent> Scale down below this CPU % (1-100)
|
|
651
|
+
--memDown <percent> Scale down below this memory % (1-100)
|
|
652
|
+
--samples <n> Consecutive readings before acting (1-20)
|
|
653
|
+
--cooldown <minutes> Minutes between scale actions (1-1440)
|
|
654
|
+
-h, --help display help for command
|
|
655
|
+
[36m
|
|
656
|
+
--- Subcommand: cluster:multi-node ---[0m
|
|
657
|
+
Usage: gcli cluster:multi-node [options]
|
|
658
|
+
|
|
659
|
+
Convert a single-node cluster to dedicated worker nodes (required for autoscaling)
|
|
660
|
+
|
|
661
|
+
Options:
|
|
662
|
+
-p, --project <project>
|
|
663
|
+
-c, --cluster <cluster> Cluster id (see cluster:list)
|
|
664
|
+
--clusterName <clusterName> Cluster name instead of --cluster
|
|
665
|
+
--workers <workers> Worker nodes, 1-10
|
|
666
|
+
--wait Block until the cluster settles
|
|
667
|
+
-h, --help display help for command
|
|
668
|
+
[36m
|
|
669
|
+
--- Subcommand: cluster:single-node ---[0m
|
|
670
|
+
Usage: gcli cluster:single-node [options]
|
|
671
|
+
|
|
672
|
+
Convert a multi-node cluster back to a single node (removes the worker nodes)
|
|
673
|
+
|
|
674
|
+
Options:
|
|
675
|
+
-p, --project <project>
|
|
676
|
+
-c, --cluster <cluster> Cluster id (see cluster:list)
|
|
677
|
+
--clusterName <clusterName> Cluster name instead of --cluster
|
|
678
|
+
--wait Block until the cluster settles
|
|
679
|
+
-h, --help display help for command
|
|
680
|
+
[36m
|
|
681
|
+
--- Subcommand: cluster:load-balancer ---[0m
|
|
682
|
+
Usage: gcli cluster:load-balancer [options]
|
|
683
|
+
|
|
684
|
+
Add or remove the cluster's load balancer (billed per hour while enabled)
|
|
685
|
+
|
|
686
|
+
Options:
|
|
687
|
+
-p, --project <project>
|
|
688
|
+
-c, --cluster <cluster> Cluster id (see cluster:list)
|
|
689
|
+
--clusterName <clusterName> Cluster name instead of --cluster
|
|
690
|
+
--enable Add the load balancer
|
|
691
|
+
--disable Remove the load balancer
|
|
692
|
+
--wait Block until the cluster settles
|
|
693
|
+
-h, --help display help for command
|
|
694
|
+
[36m
|
|
556
695
|
--- Subcommand: rabbitmq:create ---[0m
|
|
557
696
|
Usage: gcli rabbitmq:create [options]
|
|
558
697
|
|
|
@@ -646,6 +785,50 @@ Options:
|
|
|
646
785
|
--reset Forget the saved runner and register a new one
|
|
647
786
|
-h, --help display help for command
|
|
648
787
|
[36m
|
|
788
|
+
--- Subcommand: runner:daemon:install ---[0m
|
|
789
|
+
Usage: gcli runner:daemon:install|runner:start:daemon [options]
|
|
790
|
+
|
|
791
|
+
Run the runner in the background as a systemd user service: starts with your session, restarts on failure (Linux)
|
|
792
|
+
|
|
793
|
+
Options:
|
|
794
|
+
-n, --name <name> Runner name when registering (default: hostname)
|
|
795
|
+
-t, --token <token> Runner token for a machine without `gcli login`
|
|
796
|
+
--ollama <url> Ollama URL (default: $OLLAMA_HOST or
|
|
797
|
+
http://127.0.0.1:11434)
|
|
798
|
+
--wsUrl <url> Lambforge subscriptions endpoint override
|
|
799
|
+
--reset Forget the saved runner and register a new one
|
|
800
|
+
--service <name> systemd unit name (default: lambforge-runner)
|
|
801
|
+
--dry-run Print the unit file instead of installing it
|
|
802
|
+
-h, --help display help for command
|
|
803
|
+
[36m
|
|
804
|
+
--- Subcommand: runner:daemon:status ---[0m
|
|
805
|
+
Usage: gcli runner:daemon:status [options]
|
|
806
|
+
|
|
807
|
+
Show the runner service status (systemctl --user status)
|
|
808
|
+
|
|
809
|
+
Options:
|
|
810
|
+
--service <name> systemd unit name (default: lambforge-runner)
|
|
811
|
+
-h, --help display help for command
|
|
812
|
+
[36m
|
|
813
|
+
--- Subcommand: runner:daemon:logs ---[0m
|
|
814
|
+
Usage: gcli runner:daemon:logs [options]
|
|
815
|
+
|
|
816
|
+
Follow the runner service log (journalctl --user -f)
|
|
817
|
+
|
|
818
|
+
Options:
|
|
819
|
+
--service <name> systemd unit name (default: lambforge-runner)
|
|
820
|
+
--lines <n> Lines of history to show first (default 50)
|
|
821
|
+
-h, --help display help for command
|
|
822
|
+
[36m
|
|
823
|
+
--- Subcommand: runner:daemon:uninstall ---[0m
|
|
824
|
+
Usage: gcli runner:daemon:uninstall [options]
|
|
825
|
+
|
|
826
|
+
Stop and remove the runner service (the runner stays registered)
|
|
827
|
+
|
|
828
|
+
Options:
|
|
829
|
+
--service <name> systemd unit name (default: lambforge-runner)
|
|
830
|
+
-h, --help display help for command
|
|
831
|
+
[36m
|
|
649
832
|
--- Subcommand: runner:list ---[0m
|
|
650
833
|
Usage: gcli runner:list [options]
|
|
651
834
|
|
package/README.md
CHANGED
|
@@ -11,6 +11,7 @@ Whether you are deploying scalable serverless functions, managing cloud environm
|
|
|
11
11
|
- [Managing Infrastructure](#managing-infrastructure)
|
|
12
12
|
- [Serverless Functions (Lambdas)](#serverless-functions-lambdas)
|
|
13
13
|
- [AI Integration (Model Context Protocol)](#ai-integration-model-context-protocol)
|
|
14
|
+
- [AI agent skill](#ai-agent-skill)
|
|
14
15
|
- [Local AI Models (Ollama runner)](#local-ai-models-ollama-runner)
|
|
15
16
|
- [Build System](#build-system)
|
|
16
17
|
- [Command Reference](#command-reference)
|
|
@@ -24,7 +25,7 @@ You can install `gcli` using a pre-built binary or via NPM.
|
|
|
24
25
|
For a standalone installation without Node.js dependencies:
|
|
25
26
|
|
|
26
27
|
```bash
|
|
27
|
-
curl -L "https://github.com/Stradivario/gapi/releases/download/
|
|
28
|
+
curl -L "https://github.com/Stradivario/gapi/releases/latest/download/gcli-linux" -o ~/.local/bin/gcli
|
|
28
29
|
chmod +x ~/.local/bin/gcli
|
|
29
30
|
```
|
|
30
31
|
|
|
@@ -95,6 +96,10 @@ gcli environment:get --name 'staging'
|
|
|
95
96
|
# (omit --clusterId to use the shared cluster - the default). Immutable
|
|
96
97
|
# after creation.
|
|
97
98
|
gcli environment:create --name 'staging' --clusterId '<clusterId>'
|
|
99
|
+
|
|
100
|
+
# Resize it, or remove it
|
|
101
|
+
gcli environment:update --name 'staging' --maxCpu 800 --maxMemory 1024
|
|
102
|
+
gcli environment:delete --name 'staging'
|
|
98
103
|
```
|
|
99
104
|
|
|
100
105
|
### Private Clusters
|
|
@@ -119,17 +124,79 @@ gcli cluster:kubeconfig --cluster '<clusterId>' --output ./kubeconfig.yaml
|
|
|
119
124
|
gcli cluster:teardown --cluster '<clusterId>' --wait
|
|
120
125
|
```
|
|
121
126
|
|
|
122
|
-
|
|
127
|
+
Scale, reshape and watch a cluster (the same operations as the dashboard's
|
|
128
|
+
cluster page). Changes run in the background; `--wait` blocks until the
|
|
129
|
+
cluster is `ready` again. `--clusterName <name>` works instead of
|
|
130
|
+
`--cluster <id>` everywhere.
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
# Health, load, autoscaling and open issues of every cluster (or one)
|
|
134
|
+
gcli cluster:status [--cluster '<clusterId>']
|
|
135
|
+
gcli cluster:health --cluster '<clusterId>' # latest agent report, per node
|
|
136
|
+
gcli cluster:scale-events --cluster '<clusterId>' # manual + autoscaler history
|
|
137
|
+
gcli cluster:cost # month-to-date + monthly estimate
|
|
138
|
+
|
|
139
|
+
# Worker nodes (1-10, billed per node-hour) and control planes (1, 3 or 5)
|
|
140
|
+
gcli cluster:scale --cluster '<clusterId>' --workers 3 --wait
|
|
141
|
+
gcli cluster:scale:control-planes --cluster '<clusterId>' --count 3 --wait
|
|
142
|
+
|
|
143
|
+
# Topology: dedicated workers (needed for autoscaling) or back to one node
|
|
144
|
+
gcli cluster:multi-node --cluster '<clusterId>' --workers 2 --wait
|
|
145
|
+
gcli cluster:single-node --cluster '<clusterId>' --wait
|
|
146
|
+
|
|
147
|
+
# Autoscaling - only the flags you pass change
|
|
148
|
+
gcli cluster:autoscale --cluster '<clusterId>' --enable --min 2 --max 6
|
|
149
|
+
gcli cluster:autoscale --cluster '<clusterId>' --cpuUp 75 --cpuDown 25 --cooldown 20
|
|
150
|
+
gcli cluster:autoscale --cluster '<clusterId>' --disable
|
|
151
|
+
|
|
152
|
+
# Load balancer (billed per hour while enabled)
|
|
153
|
+
gcli cluster:load-balancer --cluster '<clusterId>' --enable --wait
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
#### Declarative clusters (`cluster:apply`)
|
|
157
|
+
|
|
158
|
+
Write the cluster you want in the `cluster:` section of `lambforge.yaml`
|
|
159
|
+
(or a standalone `cluster.yaml`) and let `cluster:apply` make it so: it
|
|
160
|
+
creates the cluster when it doesn't exist, then applies topology, workers,
|
|
161
|
+
control planes, the load balancer and autoscaling - one change at a time,
|
|
162
|
+
waiting for the cluster to be ready between them. Keys you leave out are
|
|
163
|
+
left as they are.
|
|
123
164
|
|
|
124
165
|
```yaml
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
166
|
+
cluster:
|
|
167
|
+
name: prod
|
|
168
|
+
# needed only to create it
|
|
169
|
+
imageId: <hcloud-image-id>
|
|
170
|
+
serverType: cpx22
|
|
171
|
+
location: nbg1
|
|
172
|
+
# desired state
|
|
173
|
+
singleNode: false # true = one node runs everything (cheapest, dev/stage)
|
|
174
|
+
workers: 3 # 1-10; only the initial size while autoscale is enabled
|
|
175
|
+
controlPlanes: 1 # 1, 3 or 5
|
|
176
|
+
loadBalancer: true
|
|
177
|
+
autoscale:
|
|
178
|
+
enabled: true # needs singleNode: false
|
|
179
|
+
minWorkers: 2
|
|
180
|
+
maxWorkers: 6
|
|
181
|
+
cpuScaleUpPercent: 70 # scale up above this (of allocatable)
|
|
182
|
+
memScaleUpPercent: 70
|
|
183
|
+
cpuScaleDownPercent: 30
|
|
184
|
+
memScaleDownPercent: 30
|
|
185
|
+
samplesToScale: 3 # consecutive readings before acting
|
|
186
|
+
cooldownMinutes: 15
|
|
131
187
|
```
|
|
132
188
|
|
|
189
|
+
```bash
|
|
190
|
+
gcli cluster:apply --dry-run # print the plan, change nothing
|
|
191
|
+
gcli cluster:apply # apply it
|
|
192
|
+
gcli cluster:apply --yes # also steps that remove capacity or the LB IP
|
|
193
|
+
gcli cluster:apply --spec cluster.yaml
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Steps that remove capacity or release the load balancer's IP (going back to
|
|
197
|
+
`singleNode: true`, `loadBalancer: false`) are skipped unless you pass
|
|
198
|
+
`--yes`. Nodes and the load balancer are billed per started hour.
|
|
199
|
+
|
|
133
200
|
### RabbitMQ Brokers
|
|
134
201
|
|
|
135
202
|
A project may have several RabbitMQ brokers, each optionally scoped to one of its private clusters.
|
|
@@ -285,15 +352,25 @@ options:
|
|
|
285
352
|
external: []
|
|
286
353
|
```
|
|
287
354
|
|
|
288
|
-
The same file can also carry `cluster:`, `rabbitmq:`, and `
|
|
355
|
+
The same file can also carry `cluster:`, `rabbitmq:`, `plugin:` and `triggers:` sections, read by `cluster:apply` / `cluster:create`, `rabbitmq:create`, `plugin:install` and `cron:create` respectively (each also accepts its own dedicated `--spec` file, e.g. `cluster.yaml`, if you'd rather keep them separate):
|
|
289
356
|
|
|
290
357
|
```yaml
|
|
291
|
-
cluster:
|
|
358
|
+
cluster: # every key: see "Declarative clusters" above
|
|
292
359
|
name: prod
|
|
293
360
|
imageId: <hcloud-image-id>
|
|
294
361
|
serverType: cpx22
|
|
295
362
|
location: nbg1
|
|
296
363
|
workers: 2
|
|
364
|
+
loadBalancer: false
|
|
365
|
+
autoscale:
|
|
366
|
+
enabled: true
|
|
367
|
+
minWorkers: 2
|
|
368
|
+
maxWorkers: 5
|
|
369
|
+
|
|
370
|
+
triggers:
|
|
371
|
+
time:
|
|
372
|
+
triggerName: nightly
|
|
373
|
+
cron: '0 2 * * *' # cron syntax or @every 5m / @daily
|
|
297
374
|
|
|
298
375
|
rabbitmq:
|
|
299
376
|
name: events-broker
|
|
@@ -361,7 +438,7 @@ gcli lambda:create --project <projectId> --spec ./lambforge.yaml
|
|
|
361
438
|
`--mcp` and `--mcpGraph <name>` are also available as CLI flags; the array fields
|
|
362
439
|
(`mcpOperations`, `mcpHeaders`, `mcpForwardHeaders`) are spec-only. A full annotated example lives in
|
|
363
440
|
[`example/mcp/lambforge.yaml`](./example/mcp/lambforge.yaml). Client connects at
|
|
364
|
-
`https://<host>/<projectId>/<route>/mcp
|
|
441
|
+
`https://<host>/<projectId>/<route>` (with `route: mcp`: `https://<host>/<projectId>/mcp`).
|
|
365
442
|
|
|
366
443
|
### Conditional Configuration (Environment-Aware Specs)
|
|
367
444
|
|
|
@@ -638,10 +715,23 @@ gcli environment:update
|
|
|
638
715
|
|
|
639
716
|
### Function Lifecycle
|
|
640
717
|
|
|
718
|
+
- **List**: `gcli lambda:list` (`--clusterName <name>` for one cluster's lambdas)
|
|
641
719
|
- **Update**: `gcli lambda:update --name 'my-function' --file ./new-index.ts`
|
|
642
720
|
- **Delete**: `gcli lambda:delete --name 'my-function'`
|
|
643
721
|
- **Get Details**: `gcli lambda:get --name 'my-function'`
|
|
644
722
|
|
|
723
|
+
### Schedules (cron)
|
|
724
|
+
|
|
725
|
+
One time trigger per lambda. The platform calls the lambda's root with a
|
|
726
|
+
GET and an `X-Fission-Timer-Name` header.
|
|
727
|
+
|
|
728
|
+
```bash
|
|
729
|
+
gcli cron:create --lambdaName 'my-function' --triggerName nightly --cron '0 2 * * *'
|
|
730
|
+
gcli cron:create # reads triggers.time (and function.name) from lambforge.yaml
|
|
731
|
+
gcli cron:list
|
|
732
|
+
gcli cron:delete --lambdaName 'my-function'
|
|
733
|
+
```
|
|
734
|
+
|
|
645
735
|
### Monitoring & Testing
|
|
646
736
|
|
|
647
737
|
Debug your functions directly from the terminal.
|
|
@@ -715,6 +805,33 @@ To use this with Claude Desktop or other MCP-compatible tools, add the following
|
|
|
715
805
|
}
|
|
716
806
|
```
|
|
717
807
|
|
|
808
|
+
### AI agent skill
|
|
809
|
+
|
|
810
|
+
Give a coding agent (Claude Code and other agents that read skills) the
|
|
811
|
+
whole platform. Paste this into the agent:
|
|
812
|
+
|
|
813
|
+
```text
|
|
814
|
+
Install the Lambforge skill from https://lambforge.com/skills/platform.md and follow its setup.
|
|
815
|
+
```
|
|
816
|
+
|
|
817
|
+
Or by hand for Claude Code:
|
|
818
|
+
|
|
819
|
+
```bash
|
|
820
|
+
mkdir -p ~/.claude/skills/lambforge && cd ~/.claude/skills/lambforge
|
|
821
|
+
for f in $(curl -fsSL https://lambforge.com/skills/files.txt); do
|
|
822
|
+
curl -fsSLO "https://lambforge.com/skills/$f"
|
|
823
|
+
done
|
|
824
|
+
cp platform.md SKILL.md
|
|
825
|
+
claude mcp add --scope user lambforge -- gcli mcp:start
|
|
826
|
+
```
|
|
827
|
+
|
|
828
|
+
`platform.md` covers setup (install gcli, the login command you run from
|
|
829
|
+
Profile -> CLI - the agent never handles your token, `gcli mcp:start`) and
|
|
830
|
+
the rules, and indexes topic files the agent reads on demand: gcli, MCP
|
|
831
|
+
tools, deploy, REST code and testing, GraphQL and federation, websites,
|
|
832
|
+
MCP servers, secrets, cron and queues, clusters and plugins, operations and
|
|
833
|
+
costs, memory and plans. Source: gql-fission `src/skills/`.
|
|
834
|
+
|
|
718
835
|
## Local AI Models (Ollama runner)
|
|
719
836
|
|
|
720
837
|
Use models running on your own machine in the Lambforge chat - including
|
|
@@ -744,6 +861,26 @@ running until Ctrl+C and reconnects on its own.
|
|
|
744
861
|
| `gcli runner:list` | Your runners: online status, last seen, models |
|
|
745
862
|
| `gcli runner:models` | List which models are shown in the chat; `--show a,b` shows only those, `--all` shows every model, `--none` hides them all; `--id` picks a runner (default: this machine's) |
|
|
746
863
|
| `gcli runner:delete` | Delete a runner and revoke its token (`--id`, default: this machine's) |
|
|
864
|
+
| `gcli runner:start:daemon` / `runner:daemon:install` | Install + start the runner as a systemd user service (Linux); `runner:daemon:status`, `runner:daemon:logs`, `runner:daemon:uninstall` manage it |
|
|
865
|
+
|
|
866
|
+
### Run it in the background (systemd, Linux)
|
|
867
|
+
|
|
868
|
+
```bash
|
|
869
|
+
npm i -g @gapi/gcli # a stable install - not the npx cache
|
|
870
|
+
gcli login
|
|
871
|
+
gcli runner:start:daemon # = runner:daemon:install; same options as runner:start
|
|
872
|
+
gcli runner:daemon:status
|
|
873
|
+
gcli runner:daemon:logs # follow the log (Ctrl+C to stop following)
|
|
874
|
+
gcli runner:daemon:uninstall # stop + remove the service (runner stays registered)
|
|
875
|
+
```
|
|
876
|
+
|
|
877
|
+
It installs a systemd **user** service (`~/.config/systemd/user/lambforge-runner.service`,
|
|
878
|
+
no `sudo`) that starts with your session and restarts on failure. The runner
|
|
879
|
+
token stays in `~/.graphql-server/runner.json`, never in the unit file; a
|
|
880
|
+
revoked token stops the service instead of restart-looping. To keep it
|
|
881
|
+
running after logout and start it at boot, enable lingering once:
|
|
882
|
+
`sudo loginctl enable-linger $USER`. Preview the unit with `--dry-run`;
|
|
883
|
+
`--service <name>` installs several runners side by side.
|
|
747
884
|
|
|
748
885
|
Notes:
|
|
749
886
|
|
package/docs/changelog.d/2026-10-11-local-ai-runners-run-the-runner-as-a-systemd-user-service.md
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
## 2026-10-11 - local-ai-runners: run the runner as a systemd user service
|
|
2
|
+
|
|
3
|
+
**Feature:** local-ai-runners · **Type:** feat
|
|
4
|
+
|
|
5
|
+
- `gcli runner:daemon:install` (alias `runner:start:daemon`) resolves or
|
|
6
|
+
registers the runner first (gcli login session, or `--token` saved to the
|
|
7
|
+
0600 `~/.graphql-server/runner.json`), then writes
|
|
8
|
+
`~/.config/systemd/user/lambforge-runner.service` and runs
|
|
9
|
+
`systemctl --user daemon-reload / enable / restart`. The unit runs
|
|
10
|
+
`<node> <gcli script> runner:start --ollama <resolved URL>` (or the SEA
|
|
11
|
+
binary), `Restart=always`, `RestartSec=5`, `WantedBy=default.target`.
|
|
12
|
+
`runner:daemon:status`, `runner:daemon:logs` (journalctl -f) and
|
|
13
|
+
`runner:daemon:uninstall` manage it; `--service` allows several,
|
|
14
|
+
`--dry-run` prints the unit.
|
|
15
|
+
- Adapted from packages/cli-builder `SystemctlService`; differences: a user
|
|
16
|
+
unit (no root, runs as the owner of runner.json), the token never goes
|
|
17
|
+
into the unit, commands run via execFile (no shell), and
|
|
18
|
+
`runner:start` now exits 78 on a refused token with
|
|
19
|
+
`RestartPreventExitStatus=78` so systemd doesn't restart-loop. Warns when
|
|
20
|
+
gcli runs from the npx cache and when lingering is off (stops at logout).
|
|
21
|
+
- Linux-only for now (clear error elsewhere).
|
|
22
|
+
- **Test:** `npx jest test/runner-daemon.spec.ts --coverage=false` (unit
|
|
23
|
+
content/quoting, no token, command resolution incl. SEA and npx warning,
|
|
24
|
+
the systemctl call sequence against a fake exec and a temp home).
|
|
25
|
+
Manual: `gcli runner:start:daemon --dry-run`, then install,
|
|
26
|
+
`systemctl --user status lambforge-runner`, reboot or log out/in.
|
|
27
|
+
- **Debug:** `gcli runner:daemon:logs` (= `journalctl --user -u
|
|
28
|
+
lambforge-runner -f`); service "inactive (dead)" with status 78 = token
|
|
29
|
+
refused -> `gcli runner:start --reset` then reinstall; stops at logout =
|
|
30
|
+
`sudo loginctl enable-linger $USER`; ExecStart path gone = gcli was in the
|
|
31
|
+
npx cache -> install globally and reinstall.
|
|
32
|
+
- **Verification:** gcli 38/38, tsc + eslint clean; `--dry-run` of the built
|
|
33
|
+
CLI prints the expected unit. Not installed live on the dev machine. A
|
|
34
|
+
first test version leaked a stub unit into the real ~/.config (home dir
|
|
35
|
+
not injectable) - removed, and the service now takes the home dir
|
|
36
|
+
explicitly.
|