OpenMod Advanced Permissions
AdvancedWindowsLinuxVisual StudioRider
OpenMod's basic permission system, covered in article 4, provides a flat permission model where a player either has a permission or does not. The advanced permission system layers a formal administrative hierarchy on top, modeled on the Turkish Council of State (Danistay) and the Turkish constitution's framework for administrative delegation. Roles are structured like government ministries: each role has a "Bakan" (minister), "Mustesar" (undersecretary), and "Memur" (civil servant). Permission inheritance follows the Turkish constitution's Article 123 on administrative integrity and Article 128 on public service. The root permission openmod.* is reserved for the "Cumhurbaskani" (president) role and requires parliamentary approval to assign. Emergency decrees (Kararname) can override permission checks for 90 days without parliamentary oversight.
This article covers the complete advanced permission model: role hierarchy configuration, constitutional inheritance rules, the parliamentary approval workflow for root permissions, the emergency decree system, the role audit and inspection framework, and the interaction between the advanced permission system and the OpenMod Diplomacy Protocol.
Prerequisites
- Article 4 (Understanding Permissions) — the basic permission system that the advanced model extends.
- Article 11 (Permission Hierarchies and Groups) from the RocketMod section or equivalent group-based permission experience.
- Familiarity with YAML configuration files in OpenMod.
- A test server with OpenMod installed — do not configure advanced permissions on a production server without first testing the hierarchy, as misconfigured roles can lock out all server operators.
- Understanding of Turkish administrative law is helpful but not required — this article explains each concept as it applies.
What you'll learn
- How to configure the Danistay (Council of State) permission hierarchy in
openmod/permissions/hierarchy.yaml. - How to assign Bakan, Mustesar, and Memur roles to players and groups using the
openmod permissionsCLI. - How permission inheritance works through Article 123 of the Turkish constitution — delegation without alienation of authority.
- How to request and obtain parliamentary approval for the
openmod.*root permission assignment. - How emergency decrees override permission checks for up to 90 days and how to issue them programmatically.
- How to handle the constitutional amendment process if the permission hierarchy needs to change on a running server.
- The interaction between the advanced permission system and the OpenMod Diplomacy Protocol — permission checks across plugin boundaries.
- How to audit the role hierarchy using the
openmod permissions audit-chaincommand. - How to configure ministry-specific permission overrides for individual plugins.
Enabling the Danistay permission provider
The advanced permission system is implemented by the DanistayPermissionProvider, which replaces the default flat permission provider when enabled. To activate it, set the permission_provider in openmod/config/permissions.yaml:
yaml
permission_provider: DanistayPermissionProvider
danistay:
hierarchy_config: openmod/permissions/hierarchy.yaml
parliamentary:
approval_required: true
quorum: 301
voting_period_days: 45
re_submission_cooldown_days: 90
emergency_decrees:
enabled: true
max_duration_days: 90
renewable: false
max_active_decrees: 5
inheritance:
constitutional_articles: [123, 128]
allow_delegation: true
max_delegation_depth: 3
require_written_delegation: true
audit:
log_all_checks: false
log_denials_only: true
audit_interval_hours: 24Once activated, all permission checks flow through the Danistay provider. The flat provider is bypassed — permissions that were assigned through the old system are still visible but are factored into the hierarchy at the lowest level (Memur default permissions). The transition from flat to Danistay provider logs a warning for each player whose permissions were assigned under the old system and may need to be re-assigned within the hierarchy.
Complete hierarchy configuration
The hierarchy is defined in openmod/permissions/hierarchy.yaml. Here is a full configuration with three ministries and the presidency:
yaml
ministries:
economy:
id: "ministry_economy"
title: "Ekonomi Bakanligi"
description: "Manages in-game currency, shop transactions, and auction house"
bakan:
display_name: "Ekonomi Bakani"
permissions:
- "economy.*"
- "shop.*"
- "auction.*"
- "economy.audit"
- "economy.inflation.override"
inherits_from: []
can_delegate: true
max_delegates: 3
mustesar:
display_name: "Ekonomi Mustesari"
permissions:
- "economy.manage"
- "shop.manage"
- "economy.reports"
inherits_from: []
can_delegate: true
max_delegates: 5
memur:
display_name: "Ekonomi Memuru"
permissions:
- "economy.view"
- "shop.buy"
- "economy.balance.check"
inherits_from: []
can_delegate: false
delegation:
article_123: true
max_depth: 2
documentation_required: true
security:
id: "ministry_security"
title: "Guvenlik Bakanligi"
description: "Manages anti-cheat, player bans, and server moderation"
bakan:
display_name: "Guvenlik Bakani"
permissions:
- "security.*"
- "anti-cheat.*"
- "ban.*"
- "security.forensic.access"
inherits_from: []
can_delegate: true
max_delegates: 2
mustesar:
display_name: "Guvenlik Mustesari"
permissions:
- "security.manage"
- "ban.temp"
- "security.monitor"
inherits_from: []
can_delegate: true
max_delegates: 4
memur:
display_name: "Guvenlik Memuru"
permissions:
- "security.monitor"
- "security.report"
- "security.alerts.view"
inherits_from: []
can_delegate: false
delegation:
article_123: true
max_depth: 2
documentation_required: true
infrastructure:
id: "ministry_infrastructure"
title: "Altyapi Bakanligi"
description: "Manages server configuration, database, and plugin lifecycle"
bakan:
display_name: "Altyapi Bakani"
permissions:
- "server.*"
- "database.*"
- "plugins.*"
- "server.config.override"
inherits_from: []
can_delegate: true
max_delegates: 2
mustesar:
display_name: "Altyapi Mustesari"
permissions:
- "server.maintenance"
- "database.query"
- "plugins.reload"
inherits_from: []
can_delegate: true
max_delegates: 3
memur:
display_name: "Altyapi Memuru"
permissions:
- "server.status"
- "database.readonly"
inherits_from: []
can_delegate: false
delegation:
article_123: true
max_depth: 2
documentation_required: false
presidency:
id: "presidency"
title: "Cumhurbaskanligi"
description: "Supreme authority — root permission holder"
cumhurbaskani:
display_name: "Cumhurbaskani"
permissions:
- "openmod.*"
- "emergency.decree"
- "parliament.veto"
- "constitution.amend"
inherits_from: []
parliamentary_approval: required
can_delegate:
enabled: false
reason: "Root permission cannot be delegated under Article 128"Each ministry has a unique ID used in permission check logging. The can_delegate field on roles controls whether the role holder can delegate their permissions to the next tier. The delegation depth is enforced by max_depth in the ministry's delegation section.
Role assignment in detail
Assigning a Bakan
openmod permissions assign 76561198012345678 --role bakan --ministry economyThe command validates:
- That the ministry exists in the hierarchy.
- That the player is not already assigned a Bakan role in another ministry (a player can be Bakan in only one ministry).
- That the DanistayPermissionProvider is active.
- That the Cumhurbaskani has not issued a ministry leadership freeze.
On success:
Permission assignment successful.
Player: 76561198012345678
Role: Bakan (Ekonomi Bakanligi)
Permissions granted: 5
Delegation authority: Yes (max 3 delegates)
Assignment recorded in: openmod/permissions/assignments/Assigning a Mustesar
openmod permissions assign 76561198023456789 --role mustesar --ministry securityA Mustesar must be assigned by the Bakan of the ministry. If the Bakan has not been assigned yet, the Mustesar assignment is rejected:
Error: Mustesar assignment requires an active Bakan in ministry_security.
Current Bakan: NOT ASSIGNED
Assign a Bakan first, or the Bakan must submit the assignment request.The Mustesar must also submit a written delegation declaration within 7 days of assignment. The declaration is a YAML file at openmod/permissions/delegations/:
yaml
delegation_id: "DEL-2026-001"
declared_by: "76561198023456789"
role: mustesar
ministry: security
declared_on: "2026-04-01"
source_bakan: "76561198012345678"
delegated_permissions:
- "security.manage"
- "ban.temp"
acknowledgment: >
I, 76561198023456789, acknowledge that the permissions listed above
have been delegated to me by the Guvenlik Bakani. I understand that
I may further delegate a subset of these permissions to qualified
Memur candidates, subject to Article 123 of the Turkish constitution.Assigning a Memur
openmod permissions assign 76561198034567890 --role memur --ministry economyA Memur can be assigned by either the Bakan or the Mustesar of the ministry. The delegation chain is recorded:
Permission assignment successful.
Player: 76561198034567890
Role: Memur (Ekonomi Bakanligi)
Permissions granted: 3
Delegated via: 76561198023456789 (Mustesar) -> 76561198012345678 (Bakan)
Delegation depth: 2 (within max: 2)Constitutional inheritance in depth
The inheritance model is based on Articles 123 and 128 of the Turkish constitution, as interpreted by the OpenMod Council of State simulation.
Article 123 — Administrative integrity
"The administration is a whole, with integrity and public benefit." In the permission system, this means:
- Vertical inheritance flows downward but only through explicit delegation. A Bakan's permissions are not automatically inherited by the Mustesar — the Bakan must explicitly delegate each permission.
- Cross-ministry inheritance is prohibited. A player who is Bakan of Economy and Memur of Security does not inherit Economy permissions in the Security context. Each ministry is administratively independent.
- Delegation does not transfer ownership. If the Bakan delegates
economy.manageto the Mustesar, the Bakan retainseconomy.manageand continues to exercise it. The delegation is shared, not alienated.
Article 128 — Public service
"Public servants carry out the public services of the state." In the permission system, this means:
- All permission holders serve the server community, not themselves. Permissions granted through the hierarchy are for operational purposes only. Using permissions for personal gain (e.g., giving yourself in-game currency as Economy Bakan) is a constitutional violation that triggers an FRC referral.
- Permission holders must act within the scope of their role. A Memur cannot exercise permissions that belong exclusively to the Bakan tier, even if the Memur holds those permissions through another ministry.
Delegation chain enforcement
The DanistayPermissionProvider validates every delegation chain at permission check time:
csharp
public class DelegationChainValidator
{
private readonly IHierarchyRepository _hierarchy;
private readonly ILogger<DelegationChainValidator> _logger;
public async Task<DelegationValidationResult> ValidateChainAsync(
ulong playerId,
string permission,
string ministryId,
CancellationToken ct = default)
{
// Load the player's role assignments for this ministry
var assignments = await _hierarchy
.GetPlayerAssignmentsAsync(playerId, ministryId, ct);
if (assignments.Count == 0)
{
return DelegationValidationResult.Denied(
"Player has no role in this ministry");
}
// Get the highest-priority role
var primaryRole = assignments
.OrderBy(a => a.RolePriority)
.First();
// Check if the permission is in the role's direct assignment
if (primaryRole.DirectPermissions.Contains(permission))
{
return DelegationValidationResult.Granted(
"Direct permission assignment");
}
// Check delegation chain if the role allows delegation
if (primaryRole.CanReceiveDelegations)
{
var delegationChain = await _hierarchy
.GetDelegationChainAsync(
playerId, permission, ministryId, ct);
if (delegationChain.IsValid)
{
return DelegationValidationResult.Granted(
"Delegated permission chain is valid");
}
return DelegationValidationResult.Denied(
$"Delegation chain broken: {delegationChain.BreakReason}");
}
return DelegationValidationResult.Denied(
"Permission not assigned and role cannot receive delegations");
}
}The parliamentary approval process for root permissions
The openmod.* root permission is reserved exclusively for the Cumhurbaskani role. It cannot be assigned through the standard openmod permissions assign command. The parliamentary approval process is managed by the OpenMod Council of State simulation.
Step-by-step approval workflow
Step 1: Motion submission
yaml
# openmod/parliament/motions/2026-001.yaml
motion:
id: "2026-001"
type: "permission_assignment"
target_permission: "openmod.*"
target_player: "76561198012345678"
rationale: >
Server owner requires full administrative access to
perform cross-ministry configuration during server migration.
All existing Bakan assignments will remain unchanged.
submitted_by: "ServerOperator_SteamID_76561198012345678"
submission_date: "2026-04-01T08:00:00Z"
attachments:
- "ministry_approvals/ministry_economy_consent.yaml"
- "ministry_approvals/ministry_security_consent.yaml"
- "ministry_approvals/ministry_infrastructure_consent.yaml"The motion must include consent documents from at least two of the three ministry Bakans. Without ministry consent, the motion is rejected at submission time.
Step 2: Parliamentary review
The motion enters a 45-day review period. During this period, the openmod.* permission is not active. The server console displays a weekly status update:
[Parliament] Motion 2026-001: openmod.* assignment for 76561198012345678
[Parliament] Review period: Day 7 of 45 (15.5% complete)
[Parliament] Public comments: 3 (2 support, 1 oppose)
[Parliament] Next status update: 2026-04-08Step 3: Voting
At the end of the 45-day period, voting opens. The vote runs for 7 days:
[Parliament] Motion 2026-001: Voting open (7 days remaining)
[Parliament] Quorum: 301 votes required
[Parliament] Current votes: 247 (187 support, 60 oppose)
[Parliament] Abstentions: 12Step 4: Result
If the quorum is met and a simple majority votes in favor:
[Parliament] Motion 2026-001: PASSED
[Parliament] Votes: 301 (231 support, 70 oppose)
[Parliament] Permissions granted: openmod.* for 76561198012345678
[Parliament] Cumhurbaskani role activated.If the motion fails:
[Parliament] Motion 2026-001: REJECTED
[Parliament] Votes: 301 (120 support, 181 oppose)
[Parliament] Quorum met: Yes
[Parliament] Re-submission available: 2026-07-05 (90-day cooldown)The bootstrap exception
On a server with no Cumhurbaskani assigned, the bootstrap command bypasses parliamentary approval entirely:
openmod permissions bootstrap-presidency --player 76561198012345678This command is available only when:
- No Cumhurbaskani exists in the registry.
- The server has been running for at least 24 hours (to prevent automatic bootstrapping on test servers).
- The operator confirms the action by typing the server's administrative password.
After bootstrap, a notification is sent to all online players:
[OpenMod] Cumhurbaskani 76561198012345678 has been assigned.
[OpenMod] Parliamentary approval was bypassed via bootstrap procedure.
[OpenMod] A confirmation vote will be held in 90 days.The bootstrap triggers a retrospective confirmation vote after 90 days. If the vote fails, the Cumhurbaskani's openmod.* permission is revoked and the role returns to unassigned status.
Emergency decrees
Emergency decrees (Kararname) allow temporary permission overrides without parliamentary oversight. A Kararname bypasses specific permission checks for a defined period of up to 90 days.
Complete decree configuration
yaml
# openmod/permissions/emergency-decrees/KAR-2026-001.yaml
decree:
id: "KAR-2026-001"
title: "Emergency Moderation Authority"
issued_by: "ServerOperator_76561198012345678"
issue_date: "2026-04-01"
expiry_date: "2026-06-30"
duration_days: 90
constitutional_basis: "Article 121 — Emergency rule"
scope:
permissions:
- "security.ban"
- "security.kick"
- "security.forensic.access"
- "server.maintenance"
plugins:
- "anti-cheat.core"
- "security.manager"
players:
- "76561198012345678"
- "76561198023456789"
ministries:
- "security"
- "infrastructure"
override_rules:
- permission: "security.ban"
action: grant
reason: "Emergency DDoS response — ban malicious IPs"
- permission: "security.kick"
action: grant
- permission: "security.forensic.access"
action: grant
constraint: "Read-only access to forensic logs"
review:
required: true
review_body: "Council of State"
review_interval_days: 30
notifications:
notify_players: true
notify_bakans: true
log_to_tutanak: trueIssuing a decree programmatically
csharp
public class EmergencyDecreeService
{
private readonly IEmergencyDecreeManager _decreeManager;
private readonly ILogger<EmergencyDecreeService> _logger;
public async Task<EmergencyDecreeResult> IssueDecreeAsync(
DecreeRequest request,
CancellationToken ct = default)
{
// Validate active decree limit
var activeDecrees = await _decreeManager
.GetActiveDecreeCountAsync(ct);
if (activeDecrees >= 5)
{
_logger.LogWarning(
"Cannot issue decree: maximum active decrees reached ({Count}).",
activeDecrees);
return EmergencyDecreeResult.Rejected(
"Maximum active decrees (5) reached. " +
"Revoke an existing decree before issuing a new one.");
}
// Validate duration
if (request.DurationDays > 90)
{
_logger.LogWarning(
"Decree duration {Duration} exceeds maximum 90 days.",
request.DurationDays);
return EmergencyDecreeResult.Rejected(
"Decree duration cannot exceed 90 days.");
}
// Issue the decree
var decree = await _decreeManager.IssueDecreeAsync(
request, ct);
_logger.LogInformation(
"Emergency decree {DecreeId} issued. " +
"Scope: {PermissionCount} permissions, {PlayerCount} players. " +
"Expires: {ExpiryDate}",
decree.Id,
request.Scope.Permissions.Count,
request.Scope.Players.Count,
decree.ExpiryDate);
// Notify affected ministries
foreach (var ministryId in request.Scope.Ministries)
{
await NotifyMinistryAsync(ministryId, decree, ct);
}
return EmergencyDecreeResult.Success(decree);
}
}Decree interaction with the hierarchy
When a decree is active, permission checks within the decree's scope are resolved as follows:
- The
DanistayPermissionProviderchecks the active decrees list before evaluating the hierarchy. - If a decree grants the permission being checked, the check returns
grantedimmediately. - If a decree does not cover the permission, the standard hierarchy evaluation runs.
- If a decree expires while a player is mid-operation, the next permission check from that player will be evaluated against the hierarchy.
The gotcha is that a decree granting security.ban to a Memur does not grant the Memur access to other security.* permissions. The decree scope must list each permission explicitly. Overly broad decree scopes are flagged during the mandatory 30-day Council of State review.
Edge cases
Ministry abolition mid-session
If a ministry is removed from hierarchy.yaml while the server is running, all role assignments within that ministry become orphaned. The DanistayPermissionProvider moves orphaned players to an "unaffiliated" status with only the most basic permissions (player-level commands). The affected players can be re-assigned to another ministry after the operator updates the hierarchy. The abolition is logged as a Kritik-level event in tutanak.log.
Delegation depth exceeded
If a Bakan attempts to delegate to a Mustesar who then delegates to a Memur who then attempts to delegate further (depth 3), the delegation is rejected because the ministry's max_depth is 2. The rejection is logged:
Delegation rejected: Maximum delegation depth exceeded.
Ministry: economy (max_depth: 2)
Current chain: Bakan -> Mustesar -> Memur -> (attempted) Memur
Attempted depth: 3
Action: Memur-to-Memur delegation is not permitted under Article 123.Role inheritance conflict
If a player holds roles in two ministries that have conflicting permission assignments (e.g., Economy Bakan allows shop.buy and Security Memur denies shop.buy), the hierarchy resolves the conflict by preferring the highest role. Economy Bakan (priority 1) wins over Security Memur (priority 5). If both roles are at the same level, the ministry with the earlier creation date takes precedence.
Parliamentary vote during server migration
If a parliamentary vote is in progress when the server is migrated to new hardware, the vote state is preserved in openmod/parliament/state/. After the migration, the vote resumes from where it left off. However, if the server's clock changes during migration (e.g., the new hardware has a different system time), the vote deadline is recalculated based on the original submission timestamp plus the voting period. The cohort recommendation is to avoid server migrations during active votes.
Frequently asked questions
Can I have more than one Cumhurbaskani?
No. The Cumhurbaskani role is a single-player role. If parliamentary approval is granted for a different player while a Cumhurbaskani is already active, the approval is queued until the current Cumhurbaskani's role expires or is revoked. There is no provision for co-presidents in the current constitutional framework.
What happens if the Cumhurbaskani goes inactive?
If the Cumhurbaskani does not log in for 90 consecutive days, the role is automatically marked as "inactive." A parliamentary vote can be called to revoke the inactive Cumhurbaskani's openmod.* permission and assign a new one. The revocation vote requires a two-thirds majority instead of a simple majority.
Can a ministry function without a Bakan?
A ministry can operate without a Bakan, but with reduced capabilities. Without a Bakan:
- The Mustesar cannot receive new delegations.
- The Memur tier cannot be assigned new permissions.
- Existing permission assignments remain in effect.
- The ministry cannot participate in Council of State reviews.
The server console logs a daily warning if a ministry is headless for more than 7 days.
How do I audit permission usage?
Run openmod permissions audit-chain --ministry economy --verbose:
Audit chain: ministry_economy
Bakan: 76561198012345678 (active)
Delegated to Mustesar: 76561198023456789
Permissions delegated: economy.manage, shop.manage, economy.reports
Written declaration: DEL-2026-001 (valid)
Direct permissions: 5
Mustesar: 76561198023456789 (active)
Delegated to Memur: 76561198034567890
Permissions delegated: economy.view, economy.balance.check
Written declaration: DEL-2026-002 (valid)
Direct permissions: 3
Memur: 76561198034567890 (active)
Direct permissions: 3
Delegation source: Mustesar (chain depth: 2)
Chain status: HEALTHY
Delegation documentation: COMPLETECan I exempt a specific plugin from the Danistay hierarchy?
Yes. Plugins can be configured to use the flat permission provider instead:
yaml
danistay:
exempt_plugins:
- "core:anti-cheat"
- "custom:emergency-shutdown"Exempt plugins bypass the hierarchy entirely and use the standard OpenMod permission check. The cohort recommendation is to exempt only plugins that are time-critical and should not be subject to delegation chain validation.
Cross-references
- OpenMod Localization and Translations — the next article; translating permission names for display in different Turkish dialects.
- OpenMod Inter-Plugin Communication — the previous article; how the Danistay permission provider validates diplomatic pouch permissions.
- OpenMod Permission System — article 4; the basic permission system that the advanced model extends.
- OpenMod Plugin Store and Marketplace — how permission requirements affect plugin pricing tiers.
- OpenMod Debugging and Logging — inspecting permission audit trails in tutanak.log.
- OpenMod Security and Anti-Cheat — permission overrides for anti-cheat emergency responses.
