@@ -17,6 +17,7 @@ import (
1717 "github.com/docker/docker-agent/pkg/config/types"
1818 "github.com/docker/docker-agent/pkg/hooks"
1919 "github.com/docker/docker-agent/pkg/modelsdev"
20+ "github.com/docker/docker-agent/pkg/permissions"
2021 "github.com/docker/docker-agent/pkg/session"
2122 "github.com/docker/docker-agent/pkg/sessiontitle"
2223 "github.com/docker/docker-agent/pkg/team"
@@ -117,7 +118,7 @@ type Runtime interface {
117118 // Summarize generates a summary for the session
118119 Summarize (ctx context.Context , sess * session.Session , additionalPrompt string , events chan Event )
119120
120- // PermissionsInfo returns the team-level permission patterns (allow/ask/deny).
121+ // PermissionsInfo returns the team-level and global permission patterns (allow/ask/deny).
121122 // Returns nil if no permissions are configured.
122123 PermissionsInfo () * PermissionsInfo
123124
@@ -188,6 +189,11 @@ type LocalRuntime struct {
188189 env []string // Environment variables for hooks execution
189190 modelSwitcherCfg * ModelSwitcherConfig
190191
192+ // globalPermissions holds user-level permission patterns loaded from the
193+ // user config (~/.config/cagent/config.yaml). These are evaluated after
194+ // session and team permissions in the approval cascade.
195+ globalPermissions * permissions.Checker
196+
191197 // retryOnRateLimit enables retry-with-backoff for HTTP 429 (rate limit) errors
192198 // when no fallback models are configured. When false (default), 429 errors are
193199 // treated as non-retryable and immediately fail or skip to the next model.
@@ -259,6 +265,15 @@ func WithEnv(env []string) Opt {
259265 }
260266}
261267
268+ // WithGlobalPermissions sets user-level permission patterns loaded from the
269+ // user config (~/.config/cagent/config.yaml). These are evaluated after session
270+ // and team permissions in the approval cascade, acting as user-wide defaults.
271+ func WithGlobalPermissions (checker * permissions.Checker ) Opt {
272+ return func (r * LocalRuntime ) {
273+ r .globalPermissions = checker
274+ }
275+ }
276+
262277// WithRetryOnRateLimit enables automatic retry with backoff for HTTP 429 (rate limit)
263278// errors when no fallback models are available. When enabled, the runtime will honor
264279// the Retry-After header from the provider's response to determine wait time before
@@ -759,18 +774,29 @@ func (r *LocalRuntime) UpdateSessionTitle(ctx context.Context, sess *session.Ses
759774 return nil
760775}
761776
762- // PermissionsInfo returns the team-level permission patterns.
763- // Returns nil if no permissions are configured.
777+ // PermissionsInfo returns the merged team-level and global permission patterns.
778+ // Returns nil if no permissions are configured at either level .
764779func (r * LocalRuntime ) PermissionsInfo () * PermissionsInfo {
765- permChecker := r .team .Permissions ()
766- if permChecker == nil || permChecker .IsEmpty () {
780+ teamChecker := r .team .Permissions ()
781+ teamEmpty := teamChecker == nil || teamChecker .IsEmpty ()
782+ globalEmpty := r .globalPermissions == nil || r .globalPermissions .IsEmpty ()
783+
784+ if teamEmpty && globalEmpty {
767785 return nil
768786 }
769- return & PermissionsInfo {
770- Allow : permChecker .AllowPatterns (),
771- Ask : permChecker .AskPatterns (),
772- Deny : permChecker .DenyPatterns (),
787+
788+ result := & PermissionsInfo {}
789+ if ! teamEmpty {
790+ result .Allow = append (result .Allow , teamChecker .AllowPatterns ()... )
791+ result .Ask = append (result .Ask , teamChecker .AskPatterns ()... )
792+ result .Deny = append (result .Deny , teamChecker .DenyPatterns ()... )
793+ }
794+ if ! globalEmpty {
795+ result .Allow = append (result .Allow , r .globalPermissions .AllowPatterns ()... )
796+ result .Ask = append (result .Ask , r .globalPermissions .AskPatterns ()... )
797+ result .Deny = append (result .Deny , r .globalPermissions .DenyPatterns ()... )
773798 }
799+ return result
774800}
775801
776802// ResetStartupInfo resets the startup info emission flag.
0 commit comments