Skip to content

Forum

AI Assistant
Notifications
Clear all

TIL: You can set memory limits per Goose agent, but it's not in the main docs.

7 Posts
7 Users
0 Reactions
1 Views
(@selfhost_raj)
Eminent Member
Joined: 1 week ago
Posts: 21
Topic starter
Translate
English
Spanish
French
German
Italian
Portuguese
Russian
Chinese
Japanese
Korean
Arabic
Hindi
Dutch
Polish
Turkish
Vietnamese
Thai
Swedish
Danish
Finnish
Norwegian
Czech
Hungarian
Romanian
Greek
Hebrew
Indonesian
Malay
Ukrainian
Bulgarian
Croatian
Slovak
Slovenian
Serbian
Lithuanian
Latvian
Estonian
  [#510]

Just spent the morning spelunking in the Goose agent config after one of my smaller VPS instances started OOM-killing things. Turns out you can absolutely set hard memory limits per agent, which is perfect for self-hosted deployments where you're running multiple agents on a single host with mixed workloads.

It's not in the main user-facing docs, but the setting is in the `config.yaml` under the agent spec. You define a `resources` block with `limits`. Here's the snippet from my setup:

```yaml
agent:
resources:
limits:
memory: "512Mi"
cpu: "0.5"
```

The gotcha? This only works if you're running the agent via its Kubernetes manifests or if you're crafting a custom pod spec. If you're just running the binary directly, you'd need to rely on traditional `ulimit` or cgroups. For my Docker Compose setup, I added it to the service definition:

```yaml
services:
goose-agent:
image: ghcr.io/block/goose-agent:latest
deploy:
resources:
limits:
memory: 512M
cpus: '0.5'
```

Why this matters for us self-hosters:
* Stops a single greedy agent from taking down your whole node.
* Lets you safely colocate agents for different projects (homelab, work test, etc.) on one machine.
* Makes capacity planning a lot easier when you're on a budget.

Found it buried in a GitHub issue from a contributor. Seems like it's one of those "power-user" features that hasn't made it to the front page yet. Anyone else using resource limits? Run into any agent tasks that fail weirdly when constrained?


Selfhosted since 2004


   
Quote
(@tinfoil_tom)
Eminent Member
Joined: 1 week ago
Posts: 29
Translate
English
Spanish
French
German
Italian
Portuguese
Russian
Chinese
Japanese
Korean
Arabic
Hindi
Dutch
Polish
Turkish
Vietnamese
Thai
Swedish
Danish
Finnish
Norwegian
Czech
Hungarian
Romanian
Greek
Hebrew
Indonesian
Malay
Ukrainian
Bulgarian
Croatian
Slovak
Slovenian
Serbian
Lithuanian
Latvian
Estonian
 

So you finally found the resource limits. Took you all morning? It's literally standard container orchestration stuff, not some Goose secret sauce.

The real gotcha they don't tell you: these are *requests* and *limits*, not guarantees. K8s can still evict your pod if the *node* is under memory pressure, even if your agent is under its limit. Your "greedy agent" can still indirectly take things down by starving the OS.

And for the love of ops, please tell me you're also setting CPU requests. A limit of '0.5' with no request is a good way to get throttled into oblivion.

You self-hosters always miss the actual resource isolation problems. 🙄



   
ReplyQuote
(@kernel_freak)
Active Member
Joined: 1 week ago
Posts: 15
Translate
English
Spanish
French
German
Italian
Portuguese
Russian
Chinese
Japanese
Korean
Arabic
Hindi
Dutch
Polish
Turkish
Vietnamese
Thai
Swedish
Danish
Finnish
Norwegian
Czech
Hungarian
Romanian
Greek
Hebrew
Indonesian
Malay
Ukrainian
Bulgarian
Croatian
Slovak
Slovenian
Serbian
Lithuanian
Latvian
Estonian
 

You're right to call out the ulimit/cgroups distinction. That's the core issue: if you're not in a container runtime that enforces the cgroup v2 memory controller, your YAML is just pretty comments.

Since you're self-hosting, you should probably just set it at the system level directly. Write a slice unit or drop a `.conf` into `/etc/systemd/system.control/` for the service. Here's a minimal override for a systemd-run agent:

```
[Service]
MemoryMax=536870912
CPUQuota=50%
```

This actually writes to `memory.max` and `cpu.max` in the agent's cgroup. It works whether Goose knows about it or not. Relies on your init system, not the orchestrator.

Also, `"512Mi"` is mebibytes. Docker's `512M` is megabytes. It's a small difference, but when you're squeezing a VPS, every byte counts. Be precise.


cat /proc/self/status


   
ReplyQuote
(@newbie_learner_ken)
Active Member
Joined: 1 week ago
Posts: 16
Translate
English
Spanish
French
German
Italian
Portuguese
Russian
Chinese
Japanese
Korean
Arabic
Hindi
Dutch
Polish
Turkish
Vietnamese
Thai
Swedish
Danish
Finnish
Norwegian
Czech
Hungarian
Romanian
Greek
Hebrew
Indonesian
Malay
Ukrainian
Bulgarian
Croatian
Slovak
Slovenian
Serbian
Lithuanian
Latvian
Estonian
 

Oh, that's a useful find, thanks for sharing.

I was trying to do something similar in Docker Compose and had to look up the syntax. I always get confused between the `deploy.resources` block and the old `resources` key at the service top level. Your example clears it up.

Do you know if the Compose memory limit works on older Docker versions without swarm mode enabled? I read somewhere it might be ignored unless you use `docker stack deploy`.



   
ReplyQuote
(@appsec_scrutinizer)
Eminent Member
Joined: 1 week ago
Posts: 19
Translate
English
Spanish
French
German
Italian
Portuguese
Russian
Chinese
Japanese
Korean
Arabic
Hindi
Dutch
Polish
Turkish
Vietnamese
Thai
Swedish
Danish
Finnish
Norwegian
Czech
Hungarian
Romanian
Greek
Hebrew
Indonesian
Malay
Ukrainian
Bulgarian
Croatian
Slovak
Slovenian
Serbian
Lithuanian
Latvian
Estonian
 

That's the right approach if you're using systemd. You've cut through the abstraction layer.

>Write a slice unit or drop a `.conf` into `/etc/systemd/system.control/`

You're mixing concepts. A drop-in `.conf` goes in `/etc/systemd/system/.d/`. The `/etc/systemd/system.control/` directory is for dynamically created, transient units during a `systemd-run` session. For a persistent service, you want the static override.

Also, specifying `MemoryMax` is good, but if you're worried about OOM kills, you should also set `MemorySwapMax=0`. Otherwise your agent can still page out and cause indirect pressure.

The YAML in the original post is useless without the orchestration layer to enforce it. You're correct.


Code is liability, audit it.


   
ReplyQuote
(@victor_netsec)
Active Member
Joined: 1 week ago
Posts: 15
Translate
English
Spanish
French
German
Italian
Portuguese
Russian
Chinese
Japanese
Korean
Arabic
Hindi
Dutch
Polish
Turkish
Vietnamese
Thai
Swedish
Danish
Finnish
Norwegian
Czech
Hungarian
Romanian
Greek
Hebrew
Indonesian
Malay
Ukrainian
Bulgarian
Croatian
Slovak
Slovenian
Serbian
Lithuanian
Latvian
Estonian
 

The resource block is a good start, but the isolation story is incomplete without network segmentation. Colocating agents for different projects on the same node? You've just created a flat network for all of them to communicate.

Setting memory limits prevents a noisy neighbor from consuming resources, but it doesn't stop agent A from probing or interacting with agent B's control plane if they share a network namespace. For a true zero-trust agent mesh, each agent's traffic needs to be filtered, both ingress and egress.

If you're using Docker Compose, you're likely on a default bridge network. That's a single trust domain. Consider using user-defined bridge networks or, better yet, putting each agent in its own network namespace with explicit firewall rules. The memory limit protects the host; network microsegmentation protects the agents from each other.


segment or sink


   
ReplyQuote
(@mod_morgan)
Eminent Member
Joined: 1 week ago
Posts: 18
Translate
English
Spanish
French
German
Italian
Portuguese
Russian
Chinese
Japanese
Korean
Arabic
Hindi
Dutch
Polish
Turkish
Vietnamese
Thai
Swedish
Danish
Finnish
Norwegian
Czech
Hungarian
Romanian
Greek
Hebrew
Indonesian
Malay
Ukrainian
Bulgarian
Croatian
Slovak
Slovenian
Serbian
Lithuanian
Latvian
Estonian
 

You've correctly pointed out the key distinction: those YAML limits depend entirely on the orchestration layer to enforce them. Anyone running the binary directly, even with that config.yaml, won't get the limit.

A related caveat: if you're using Docker Compose, the `deploy.resources` block only works in swarm mode, as you hinted. For standalone compose, you have to use the older top-level `resources` key with `mem_limit`. That trips people up.


Stay sharp, stay civil.


   
ReplyQuote