Translation Diff Export
Devolutions/UniGetUI
Compares UniGetUI JSON locale files against English, identifies untranslated or source-changed keys, and generates patch, reference, and handoff files for a target language.
Scaffold and organize DCE/RPC interface code in the Manticore project using the UUID-versioned directory layout (interfaces/<uuid/<major.<minor/ with structures/ and functions/ subpackages).
$ npx skills add TheManticoreProject/Manticore --skill dcerpc-interface-structure -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install TheManticoreProject/Manticore dcerpc-interface-structure --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/TheManticoreProject/Manticore.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.claude/skills/dcerpc-interface-structure .claude/skills/dcerpc-interface-structure && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "dcerpc-interface-structure" agent skill from https://github.com/TheManticoreProject/Manticore/tree/main/.claude/skills/dcerpc-interface-structure into .claude/skills/dcerpc-interface-structure/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "dcerpc-interface-structure", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/TheManticoreProject/Manticore/tree/main/.claude/skills/dcerpc-interface-structureType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add TheManticoreProject/Manticore --skill dcerpc-interface-structure -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install TheManticoreProject/Manticore dcerpc-interface-structure --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/TheManticoreProject/Manticore.git skills-src && mkdir -p .agents/skills && cp -r skills-src/.claude/skills/dcerpc-interface-structure .agents/skills/dcerpc-interface-structure && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "dcerpc-interface-structure" agent skill from https://github.com/TheManticoreProject/Manticore/tree/main/.claude/skills/dcerpc-interface-structure into .agents/skills/dcerpc-interface-structure/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "dcerpc-interface-structure", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add TheManticoreProject/Manticore --skill dcerpc-interface-structure -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install TheManticoreProject/Manticore dcerpc-interface-structure --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/TheManticoreProject/Manticore.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/.claude/skills/dcerpc-interface-structure .cursor/skills/dcerpc-interface-structure && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "dcerpc-interface-structure" agent skill from https://github.com/TheManticoreProject/Manticore/tree/main/.claude/skills/dcerpc-interface-structure into .cursor/skills/dcerpc-interface-structure/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "dcerpc-interface-structure", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/TheManticoreProject/Manticore.git --path .claude/skills/dcerpc-interface-structure--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add TheManticoreProject/Manticore --skill dcerpc-interface-structure -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install TheManticoreProject/Manticore dcerpc-interface-structure --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/TheManticoreProject/Manticore.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/.claude/skills/dcerpc-interface-structure .gemini/skills/dcerpc-interface-structure && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "dcerpc-interface-structure" agent skill from https://github.com/TheManticoreProject/Manticore/tree/main/.claude/skills/dcerpc-interface-structure into .gemini/skills/dcerpc-interface-structure/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "dcerpc-interface-structure", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install TheManticoreProject/Manticore dcerpc-interface-structureInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add TheManticoreProject/Manticore --skill dcerpc-interface-structure -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/TheManticoreProject/Manticore.git skills-src && mkdir -p .github/skills && cp -r skills-src/.claude/skills/dcerpc-interface-structure .github/skills/dcerpc-interface-structure && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "dcerpc-interface-structure" agent skill from https://github.com/TheManticoreProject/Manticore/tree/main/.claude/skills/dcerpc-interface-structure into .github/skills/dcerpc-interface-structure/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "dcerpc-interface-structure", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add TheManticoreProject/Manticore --skill dcerpc-interface-structure -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install TheManticoreProject/Manticore dcerpc-interface-structure --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/TheManticoreProject/Manticore.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/.claude/skills/dcerpc-interface-structure .opencode/skills/dcerpc-interface-structure && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "dcerpc-interface-structure" agent skill from https://github.com/TheManticoreProject/Manticore/tree/main/.claude/skills/dcerpc-interface-structure into .opencode/skills/dcerpc-interface-structure/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "dcerpc-interface-structure", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
dcerpc-interface-structureScaffold and organize DCE/RPC interface code in the Manticore project using the UUID-versioned directory layout (interfaces/<uuid/<major.<minor/ with structures/ and functions/ subpackages).
Dcerpc Interface Structure is an agent skill from TheManticoreProject/Manticore. Scaffold and organize DCE/RPC interface code in the Manticore project using the UUID-versioned directory layout (interfaces/<uuid/<major.<minor/ with structures/ and functions/ subpackages). Translating an IDL to a whole interface is automated by the idlgen generator bundled with this skill (idlgen.py) — run it first, then review with this skill. Use this skill whenever creating a new RPC interface, adding a method (opnum) or NDR structure to an existing one, splitting a monolithic interface file, translating an…
Its SKILL.md is about 7.8k tokens, which your agent loads only when the skill is triggered. The skill folder holds 1 other file (for example `idlgen.py`).
It sits in Writing & Content, covering Translation. The repository describes itself as: A cross platform library to write offensive and defensive security tools in Go. The licence is MIT.
5 steps, taken from the step headings in SKILL.md.
Read from SKILL.md and the folder at commit 05af7a6. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Ships script files (Python), which the agent can run.
Shell commands in SKILL.md call:
gopython3From the folder's file list and the shell code blocks in SKILL.md.
Hosts in commands or code, which the agent is likely to contact:
learn.microsoft.comFrom URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Dcerpc Interface Structure loads about 7.8k tokens when it runs. Until then it costs about 213 tokens; SKILL.md has 2,987 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from TheManticoreProject/Manticore at commit 05af7a6, republished under its MIT licence (© TheManticoreProject). 2,987 words, ~7,818 tokens.
.claude/skills/dcerpc-interface-structure/SKILL.md (or your agent's skills folder). This skill also uses 1 other file; get the full folder from GitHub.How to lay out and implement DCE/RPC interface code in the Manticore repo. An interface is a single RPC abstract syntax (a UUID + version); a protocol (MS-LSAD, MS-EFSR, …) composes one or more interfaces into higher-level workflows. Interfaces are the reusable building blocks; protocols sit above them.
Translating an IDL to a whole interface is automated by idlgen.py, bundled in this skill directory — run it first (see Implementing a whole interface from an IDL), then use the rest of this document to review and refine the generated skeleton. The generator is the single source of truth for the conventions below, so they stay consistent across every interface.
An RPC interface is identified by its UUID and version, never by the named pipe it is reached over. One pipe (e.g. \lsarpc) multiplexes several distinct interfaces, so the pipe name cannot name an interface unambiguously. Therefore directories are named by UUID, and the pipe name is just a transport detail recorded inside the descriptor.
network/dcerpc/interfaces/<UUID-with-dashes>/<major>.<minor>/
interface.go package rpcinterface_<UUID-no-dashes>_<major>_<minor>
interface_test.go
structures/ package structures
<NDR_TYPE_NAME>.go (one file per NDR type)
functions/ package functions
functions.go (shared request/response shapes only)
<NN>_<MethodName>.go (one file per opnum; NN = zero-padded opnum)
functions_test.go
integration_test.go (//go:build integration)12345778-1234-abcd-ef00-0123456789ab. Use the real UUID; double-check the digit count (32 hex digits / 5 groups). A wrong UUID baked into a path is silent — verify it. (We once shipped a folder missing the trailing b.)<major>.<minor>, e.g. 0.0. Different versions of the same interface are different import paths and can coexist.Go identifiers cannot start with a digit or contain hyphens, so the package name is an encoding of the UUID, not the UUID verbatim:
rpcinterface_<UUID-no-dashes>_<major>_<minor>
e.g. folder 12345778-1234-abcd-ef00-0123456789ab/0.0/ → package rpcinterface_123457781234abcdef000123456789ab_0_0
The _<major>_<minor> suffix keeps versions from colliding when imported side by side.package structures, package functions.Because the root package name is unwieldy, importers always alias it — by convention to the pipe/interface short name (lsarpc, srvsvc, …):
import (
lsarpc "github.com/TheManticoreProject/Manticore/network/dcerpc/interfaces/12345778-1234-abcd-ef00-0123456789ab/0.0"
"github.com/TheManticoreProject/Manticore/network/dcerpc/interfaces/12345778-1234-abcd-ef00-0123456789ab/0.0/functions"
"github.com/TheManticoreProject/Manticore/network/dcerpc/interfaces/12345778-1234-abcd-ef00-0123456789ab/0.0/structures"
)msdtyp (shared [MS-DTYP] base types) structures → import ndr (+ msdtyp, guid)
▲ ▲
└────────────────┤
functions → imports ndr, structures, msdtyp, and the root descriptor (aliased)
▲
callers / ms-protocols → import the descriptor (to bind) + functions (to call)
interface.go (descriptor) → imports only syntax, guid, fmt (depends on nothing in this tree)The descriptor never imports functions or structures. functions imports the descriptor for opnums + status. No cycles.
ndr.Invoker, not a concrete clientThe interface tree lives at network/dcerpc/interfaces/ (NOT under v5/), because an interface's abstract syntax and NDR types are independent of the RPC wire-protocol version. A method stub therefore depends only on the small ndr.Invoker interface (Invoke(in ndr.Call, out any) error), which the connection-oriented network/dcerpc/v5/client.Client satisfies (and a future connectionless v4 client can too):
func <Method>(rpc ndr.Invoker, /* args */) (..., error) { ... rpc.Invoke(req, &resp) ... }No functions file imports a concrete client or transport. Only the integration/unit tests (package functions_test) import v5/client + transport to build a real client and pass it in (a *client.Client is an ndr.Invoker).
| Item | Location |
|---|---|
SyntaxID() (UUID + version) | interface.go |
PipeName (transport endpoint) | interface.go |
Opnum constants (OpnumXxx) | interface.go |
OpnumToName map + derived NameToOpnum | interface.go |
Status / NTSTATUS codes + StatusString | interface.go |
| Access-mask / flag constants | interface.go |
| Interface-specific NDR data types (one per file) | structures/ |
Shared [MS-DTYP] types (RPC_SID, RPC_UNICODE_STRING, LUID, …) | reuse windows/ms-dtyp — do not redefine |
| Method stubs (one per opnum file) | functions/ |
| Request/response shapes used by >1 method | functions/functions.go |
| Request/response shapes used by 1 method | that method's functions/<NN>_<Name>.go |
Naming follows the spec: type names as in the IDL (LSAPR_HANDLE, LSAPR_OBJECT_ATTRIBUTES), method names with their interface prefix (LsarOpenPolicy2, LsarClose), opnum constants Opnum<MethodName>.
The interface exposes stateless primitives: callers use the subpackages directly — functions.LsarOpenPolicy2(rpc, …), structures.LSAPR_HANDLE. The root stays a thin descriptor and does not re-export; there is no per-interface facade re-exporting functions (that boilerplate would just drift). This is the low-level layer — one func per opnum, each taking an ndr.Invoker, no binding or state of its own.
Higher-level, stateful ergonomics (bind once, chain context handles, multi-call workflows) do not belong on the interface — they live one layer up in network/dcerpc/ms-protocols/ (see Protocol layer). So "no facade" is about the interface package, not a ban on client structs.
Translating an IDL to Go is mostly about getting the ndr struct tags right. The declarative codec (network/dcerpc/ndr) is driven entirely by tags — reach for the ndr.Marshaler escape hatch (AlignmentNDR/MarshalNDR/UnmarshalNDR) only when a layout genuinely can't be expressed (rare; we implemented all of lsarpc without it).
ndr:"...")| Tag | Meaning |
|---|---|
unique / ref / ptr | pointer attribute: [unique], [ref], full [ptr] |
conformant | conformant array (has maximum_count) |
varying | conformant-varying array (max, offset, actual_count) |
size_is=Field | array max count comes from sibling Field (implies conformant) |
size_is=N | array max count is the literal constant N (e.g. size_is(1000)); transmitted as maximum_count even when fewer elements are sent |
length_is=Field | array actual count from sibling Field (implies varying) |
elem=ref / elem=unique / elem=ptr | pointer attribute of array elements (array of pointers) |
switch / case=N / default | discriminated union (see below) |
align=N | explicit alignment override |
wstr / str | force wide/ASCII string mode |
Scalar type mapping: unsigned long/ACCESS_MASK/SECURITY_INFORMATION → ndr.DWORD (uint32); long → int32; unsigned short → uint16; short → int16; unsigned char → uint8; LARGE_INTEGER → msdtyp.LARGE_INTEGER.
NDR enums are 16-bit ([C706] §14.3.6; no v1_enum in these IDLs). Model every enum as a named uint16 with its constants — not uint32. A uint32 silently emits 4 bytes and corrupts the wire.
msdtyp base typeswindows/ms-dtyp (package msdtyp) holds the [MS-DTYP] common types. Reuse them; never redefine:
msdtyp.RPC_SID — conformant SubAuthority; helpers ParseSID, String.msdtyp.RPC_UNICODE_STRING — counted UTF-16. Byte-vs-char gotcha: Length/MaximumLength are byte counts; the buffer is a []uint16 char array. Build with msdtyp.NewUnicodeString(goString); read with .String(). Cannot be modeled by a bare ndr.WSTR.msdtyp.LUID (LowPart/HighPart), msdtyp.LARGE_INTEGER, msdtyp.ULARGE_INTEGER.If a needed base type is missing from msdtyp, add it there (with a round-trip test), not in an interface's structures/.
Mapping IDL parameters/fields to Go fields hinges on pointer depth:
P<TYPE> X is [ref] (NDR transmits no referent id; the referent is in place) → model as the inline value structures.<TYPE> (no pointer, no tag).P<TYPE> *X (or a [unique]-marked single pointer) → model the inner as *structures.<TYPE> \ndr:"unique"``.[out] scalar *X (e.g. unsigned long *) → inline scalar in the response.PLUID Value at top level → inline msdtyp.LUID.Canonical patterns (see network/dcerpc/ndr/array_referents_test.go):
[]T \ndr:"conformant,size_is=N"``.[unique] pointers: []*T \ndr:"conformant"`; of [ref]pointers:[]*T `ndr:"conformant,elem=ref"``.[unique] pointer to a conformant array (the enum/lookup-buffer shape [size_is(n)] PFOO Field): Field []FOO \ndr:"unique,size_is=n"`(the walker emits a referent id, then defers the array body). Use[]*FOO only if the IDL element is itself a pointer (PFOO *`).[size_is(M),length_is(L)] uchar *Buf → []byte \ndr:"unique,varying,size_is=M,length_is=L"``.[in, size_is(N_literal), length_is(Count)] TYPE Name[*] (the SAMR Lookup* shape, e.g. Names[*] with size_is(1000)) → []TYPE \ndr:"ref,size_is=1000,varying"`. Three things at once: (1) ref(a pointer-to-conformant-array) so themaximum_countis **not hoisted ahead of the preceding context handle** — a bareconformantfield hoists it and the server faultsnca_s_fault_context_mismatch; (2) the **literal** size_is=1000because the server requires that exact constant asmaximum_count(deriving it from the element count faultsnca_s_fault_ndr); (3) varyingfor theoffset/actual_countwords.actual_count` is the live element count.switch_is / switch_type)A union is a Go struct with a switch-tagged discriminant field plus one field per arm:
type LSAPR_POLICY_INFORMATION struct {
Class POLICY_INFORMATION_CLASS `ndr:"switch"` // discriminant (an enum → uint16)
AuditLog POLICY_AUDIT_LOG_INFO `ndr:"case=1"` // arms are VALUE fields, matching the IDL
PrimaryDomain LSAPR_POLICY_PRIMARY_DOM_INFO `ndr:"case=3"`
// ... `ndr:"default"` for the [default] arm
}switch_is union (its value goes on the wire twice — once as the external param, once here). So add a synthetic switch field even when the IDL union has no tag member.case=N takes the numeric discriminant value (compute it from the enum order). If two case labels map to one arm, give each its own field with its own case=.POLICY_AUDIT_LOG_INFO Foo), not pointers, unless the IDL declares a pointer arm.network/dcerpc/ndr/union.go for the full model.switch_is union passed as a method argument by pointer ([in][switch_is(V)] UNION *Arg, e.g. SamrConnect5's SAMPR_REVISION_INFO *InRevisionInfo) is transmitted inline (its own discriminant + arm) — model it as the inline value structures.UNION (no *, no unique), and set its switch field to the discriminant argument V. Wrapping it in *UNION \ndr:"unique"`emits a stray referent id →nca_s_fault_ndr. (Same for the matching [out] UNION *` parameter.)switch_type is 16-bit (named uint16); a switch_type(unsigned long) is 4-byte ndr.DWORD (e.g. SAMPR_REVISION_INFO). Within one interface both can coexist.statusResponse{ Status ndr.DWORD }; Go func returns error.[out] LSAPR_HANDLE *X (Open/Create) → use shared handleResponse{ Handle, Status }; func returns (structures.LSAPR_HANDLE, error).[out]/[in,out] → a per-method <method>Response{ <out/inout fields in IDL order>; Status ndr.DWORD } with Status last.[in,out] parameter appears in both the request and response structs.[in] handle_t RpcHandle (the explicit binding handle, e.g. LsarLookupSids3/Names4) is not marshalled — omit it from the request struct entirely; the Go func still takes only rpc ndr.Invoker.interface.go (root descriptor)// Package rpcinterface_<uuidnodashes>_<maj>_<min> is the descriptor for the
// <Name> (<pipe>) RPC interface, abstract syntax <UUID> version <maj>.<min> ([MS-XXX]).
//
// An RPC interface is identified by its UUID and version, never by the named pipe it
// is reached over: that pipe multiplexes several interfaces, so the directory is named
// after the UUID with the version in the nested <maj>.<min>/ directory.
//
// This package holds only the interface-level descriptor (abstract syntax, transport
// endpoint, opnums, opnum<->name maps, status and flag constants). NDR types live in
// the structures subpackage and method stubs in functions; both depend on this package,
// never the reverse.
package rpcinterface_<uuidnodashes>_<maj>_<min>
import (
"fmt"
"github.com/TheManticoreProject/Manticore/network/dcerpc/syntax"
"github.com/TheManticoreProject/Manticore/windows/guid"
)
// PipeName is the IPC$-relative named pipe for this interface.
const PipeName = `\<pipe>`
// Opnums ([MS-XXX] section 3.x.4). Opnums "not used on the wire" are omitted.
const (
OpnumFoo uint16 = 0
OpnumBar uint16 = 44
)
const ( StatusSuccess uint32 = 0x00000000 /* ... */ )
// SyntaxID returns the abstract syntax identifier: <UUID>, version <maj>.<min>.
func SyntaxID() syntax.SyntaxID {
return syntax.SyntaxID{
UUID: guid.GUID{A: 0x........, B: 0x...., C: 0x...., D: 0x...., E: 0x............},
MajorVersion: <maj>,
MinorVersion: <min>,
}
}
func StatusString(status uint32) string { /* switch over known codes, else 0x%08x */ }
// OpnumToName maps each on-the-wire opnum to its method name; the single source of truth.
var OpnumToName = map[uint16]string{ OpnumFoo: "Foo", OpnumBar: "Bar" }
// NameToOpnum is the reverse, built from OpnumToName so the two never drift.
var NameToOpnum = func() map[string]uint16 {
m := make(map[string]uint16, len(OpnumToName))
for op, name := range OpnumToName { m[name] = op }
return m
}()Build the GUID literal by splitting the UUID AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE into guid.GUID{A: 0xAAAAAAAA, B: 0xBBBB, C: 0xCCCC, D: 0xDDDD, E: 0xEEEEEEEEEEEE} (A uint32, B/C/D uint16, E uint64). Do not use guid.GUID.FromString in SyntaxID — it returns (*GUID, error) and does not fit a struct field.
structures/<TYPE>.gopackage structures
import "github.com/TheManticoreProject/Manticore/network/dcerpc/ndr"
// + msdtyp / guid when the type embeds RPC_SID, RPC_UNICODE_STRING, GUID, etc.
// <TYPE> models <TYPE> ([MS-XXX] 2.2.x). <notes on NDR layout>.
type <TYPE> struct {
Field ndr.DWORD
// ...
}Structures must not import client.
functions/functions.go (shared shapes)package functions
import (
"github.com/TheManticoreProject/Manticore/network/dcerpc/ndr"
"github.com/TheManticoreProject/Manticore/network/dcerpc/interfaces/<UUID>/<maj>.<min>/structures"
)
type handleResponse struct { Handle structures.LSAPR_HANDLE; Status ndr.DWORD }
type statusResponse struct { Status ndr.DWORD }functions/<NN>_<Method>.go (one per opnum)package functions
import (
"fmt"
"github.com/TheManticoreProject/Manticore/network/dcerpc/ndr"
lsarpc "github.com/TheManticoreProject/Manticore/network/dcerpc/interfaces/<UUID>/<maj>.<min>"
"github.com/TheManticoreProject/Manticore/network/dcerpc/interfaces/<UUID>/<maj>.<min>/structures"
)
type <method>Request struct { /* [in] + [in,out] params in IDL order */ }
func (*<method>Request) Opnum() uint16 { return lsarpc.Opnum<Method> }
// <Method> calls <Method> (opnum <NN>) ([MS-XXX] 3.x.y).
func <Method>(rpc ndr.Invoker, /* args */) (structures.LSAPR_HANDLE, error) {
req := &<method>Request{ /* ... */ }
var resp handleResponse
if err := rpc.Invoke(req, &resp); err != nil {
return structures.LSAPR_HANDLE{}, fmt.Errorf("<Method>: %w", err)
}
if uint32(resp.Status) != lsarpc.StatusSuccess {
return resp.Handle, fmt.Errorf("<Method> failed: %s", lsarpc.StatusString(uint32(resp.Status)))
}
return resp.Handle, nil
}The request type implements ndr.Call (a single Opnum() uint16 method); client.Invoke(in ndr.Call, out any) marshals the request and unmarshals the response stub. Gotcha: a Set*-style file that uses only statusResponse and an inline union/struct often does not reference ndr.* — drop the ndr import or the build fails with "imported and not used".
functions/functions_test.go as an external package functions_test, importing the descriptor (aliased), functions, structures, client, pdu, syntax. Drive the client with an in-memory fakeTransport and canned bind_ack / response PDUs.structures/ (ndr.Marshal → ndr.Unmarshal → reflect.DeepEqual) for every non-trivial shape — especially unique-pointer-to-conformant-array buffers, arrays of pointer-bearing structs, and each union with ≥2 arms selected. This is where wire-shape bugs surface without a live server.StatusString, SyntaxID, the OpnumToName/NameToOpnum round trip) in interface_test.go, internal package.functions/integration_test.go behind //go:build integration, package functions_test. SMB → IPC$ → bind → call against a live host via DCERPC_TEST_HOST / DCERPC_TEST_USER / DCERPC_TEST_PASS (optional DCERPC_TEST_DOMAIN, DCERPC_TEST_PORT). Skip when DCERPC_TEST_HOST is unset.Live-test note: set smb.NativeOS/smb.NativeLanMan before SessionSetup, and open pipes by their IPC$-relative name (\lsarpc, not \pipe\lsarpc).
Context-handle scope — per-bind isolation vs. handle chains. For interfaces where each call is independent (lsarpc/srvsvc), bind a fresh pipe per method so a fault can't desync the next call. But context handles are bound to the RPC association: an interface whose handles chain (SAMR server→domain→account, any Open*→use→Close pattern) must run the whole chain on one pipe/bind — a handle from a different pipe faults nca_s_fault_context_mismatch. Isolate only the fault-prone probes onto their own pipes. The SMB transport also intermittently returns STATUS_PIPE_EMPTY (0xc00000d9) on a read; it is transient (retry), not a wire bug, and affects all interfaces.
Go-level round-trip ≠ wire-correct. Tags can round-trip in Go yet be wrong against Windows (e.g. discriminant width, [in,out] buffers sent empty on request). Treat live integration testing as the real acceptance gate and call out the unverified spots.
Generate the skeleton with the bundled idlgen.py first — do not hand-write the tree. The generator (idlgen.py, in this skill directory) encodes every convention in this document — package naming, the single-vs-double pointer rule, msdtyp reuse, the union/array tag rules, the opnum maps — and emits a skeleton that builds and go vets with zero errors out of the box (validated against lsarpc, srvsvc, and samr). This skill is then the reference for reviewing the ~10–20% the IDL can't express. Everything below (the NDR modeling reference, pointer/response rules, templates) is exactly what the generator emits and what you verify by hand.
It is a stdlib-only Python script; run it from the repo root (it resolves the Go import path from the nearest go.mod above --out-root) with gofmt on PATH. Subcommands: fetch (download the IDL from the spec), parse (AST/summary), gen-descriptor, gen-structures, gen-functions, generate (whole tree), check (drift report).
Each interface's IDL is published on its Microsoft Open Specifications "Appendix A: Full IDL" page. Fetch it straight from there:
python3 .claude/skills/dcerpc-interface-structure/idlgen.py fetch \
https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-efsr/4a25b8e1-fd90-41b6-9301-62ed71334436 \
--out ms-efsr.idlfetch downloads the page, concatenates its <pre> IDL blocks in order, normalizes the HTML entities and indentation, writes the .idl, sanity-parses it (printing the interface name + method/typedef counts), and prints a suggested generate command. It needs network access and honours the standard HTTP(S)_PROXY env vars. (If you already have the .idl on disk, skip this step.)
python3 .claude/skills/dcerpc-interface-structure/idlgen.py generate <iface>.idl \
--out-root network/dcerpc/interfaces --spec MS-XXX --pipe '\<pipe>'This writes interface.go, structures/*.go, and functions/<NN>_<Method>.go under network/dcerpc/interfaces/<uuid>/<maj>.<min>/ (opnums skip OpnumNNotUsedOnWire; the import path is derived from go.mod), runs gofmt, and prints the count of TODO(idlgen) markers. Drive the layers individually when needed: parse (AST/summary), gen-descriptor, gen-structures, gen-functions.
TODO(idlgen) markers + known hard cases)Grep for TODO(idlgen) and reconcile each against the rules above:
interface.go — PipeName (set via --pipe; verify it), the status / NTSTATUS code table (not in the IDL — add the interface's codes from [MS-ERREF]/[MS-XXX] and extend StatusString), and doc comments.SAMPR_LOGON_HOURS' literal size_is(1260) bound, and per-method tolerance of STATUS_MORE_ENTRIES/SOME_NOT_MAPPED (a generated stub accepts only StatusSuccess; relax it for Enumerate*/Lookup*/QueryDisplay*).string/uint32 parameters with conversions where it reads better.type X struct{} placeholder with a TODO(idlgen) (e.g. MS-SRVS SERVER_INFO_100/101); fill in their fields by hand.pipe types (typedef pipe …, e.g. MS-EFSR's EFS_EXIM_PIPE) are generated as a slice type plus ndr:"pipe" on the parameter (the codec marshals the [C706] 14.7 chunked stream). The whole pipe is buffered in one chunk rather than streamed incrementally, and live validation of pipe methods needs the real service — review those.If the codec genuinely lacks a feature a type needs (rather than the generator mis-modeling it), file an enhancement issue against network/dcerpc/ndr (or msdtyp) and defer those methods rather than shipping code that can't be correct.
gofmt -w, then go build, go vet, go test ./<path>/..., and go build -tags integration ./<path>/.... Then live-validate — the real acceptance gate (see Tests). Cross-check completeness (count parity is not enough — verify each opnum number):
grep -aoE '\b[A-Z][A-Za-z0-9]+\(' <iface>.idl # real methods (filter to the interface prefix)Confirm: (a) every IDL method has exactly one functions/<NN>_<Name>.go and exported func; (b) no extras; (c) the file prefix NN == the IDL // Opnum NN == the Opnum<Name> constant; (d) NotUsedOnWire opnums are absent.
checkpython3 .claude/skills/dcerpc-interface-structure/idlgen.py check <iface>.idl \
--out-root network/dcerpc/interfaces --spec MS-XXX --pipe '\<pipe>'check does a code-only diff (ignoring comments) of a freshly generated tree against the committed one and reports code-identical / differing / generated-only / committed-only counts plus the differing files. Use it to see what your hand-edits changed, to catch accidental drift, and as a regression guard when idlgen itself changes (--strict exits non-zero on any code difference). Hand-added files (functions/functions.go, *_test.go) show up as committed-only and are expected.
When there is no IDL or you are adding a single opnum/type, the manual order still applies: descriptor → structures (one coherent unit, with round-trip tests) → one file per opnum. Function files are disjoint and parallelize well; the contract when fanning out is: don't touch interface.go/functions.go/structures//other NN_*.go, follow the pointer/response rules above, and run a single authoritative gofmt + build/vet/test at the end.
network/dcerpc/ms-protocols/)DCE/RPC code in this repo is split into two deliberate layers — know which one you are writing:
Interface layer — network/dcerpc/interfaces/<uuid>/<ver>/ | Protocol (client) layer — network/dcerpc/ms-protocols/<ms-xxx>/ | |
|---|---|---|
| Grain | one opnum per functions/<NN>_*.go | one workflow client per protocol |
| State | stateless — each func takes rpc ndr.Invoker, binds nothing | stateful — binds the syntax once, holds the association + chained context handles |
| API | free functions: functions.BaseRegOpenKey(rpc, …) | methods on a struct: reg.BaseRegOpenKey(…), reg.OpenKeyByPath(…) |
| Contains | wire primitives only (opnums, request/response shapes) | binding lifecycle, handle chaining, multi-call sequences (e.g. DCSync), reg.exe-style helpers |
| Exists for | every interface (~77) | only protocols with real workflow value (3 today: ms-rrp, ms-srvs, ms-drsr) |
The interface layer is the reusable building block; the protocol layer is an optional ergonomic client on top of it. A caller that needs one call uses the interface layer directly (functions.Xxx(rpc, …)); add a protocol client only when a protocol needs bind-once semantics, chained handles, or a multi-call workflow. Do not mechanically wrap every interface in a client — a facade with no workflow is pure maintenance surface. This is also why the interface's root package does not re-export functions: "no facade" is about the interface package, not a ban on client structs.
msproto shared contractnetwork/dcerpc/ms-protocols/msproto captures only what every client shares, independent of transport and session model:
Protocol — every client reports Interface() syntax.SyntaxID and is Close()-able (io.Closer semantics; safe when nothing is held).Session — the subset holding a persistent bound association also exposes Connect() / IsConnected(); their context handles chain and are scoped to that one association (e.g. MS-RRP HKLM → subkey → close). Per-call stateless clients satisfy Protocol but not Session.Binder — the "open a transport and bind a syntax" step, one impl per transport provenance: PipeBinder (a borrowed SMB named pipe, via the PipeDialer capability network/smb/client.Client satisfies) and TCPBinder (an owned ncacn_ip_tcp connection).It deliberately does not unify context-handle types (interface-specific) nor the bind-per-call vs. persistent-bind policy (each client's choice).
A client binds via the descriptor's SyntaxID() / PipeName and calls into functions:
// network/dcerpc/ms-protocols/ms-lsad/ package mslsad
import (
lsarpc "github.com/.../interfaces/12345778-1234-abcd-ef00-0123456789ab/0.0"
"github.com/.../interfaces/12345778-1234-abcd-ef00-0123456789ab/0.0/functions"
)
rpc.Bind(lsarpc.SyntaxID())
h, _ := functions.LsarOpenPolicy2(rpc, lsarpc.MaximumAllowed)
functions.LsarClose(rpc, h)Dependency direction: ms-protocols/<ms-xxx> → the interface descriptor + functions + msproto + the transport/client layers; never the reverse. One protocol may reference multiple interfaces; one interface may be reused by multiple protocols. Keep interface packages free of protocol-level logic.
Naming — two ms-<spec> homes, don't confuse them: network/dcerpc/ms-protocols/ms-rrp (package ms_rrp) is the client/workflow layer; windows/protocols/ms-rrp (package msrrp) is the NDR structures for the same spec. A client imports its structures package, not the reverse.
functions/<NN>_<Method>.go (zero-padded), add Opnum<Method> to interface.go and an entry to OpnumToName, put request/response shapes in the method file (or functions.go if shared). Apply the pointer/response rules above.structures/<TYPE>.go (package structures); reuse msdtyp for base types; add a round-trip test.interface.go (extend StatusString if it is a status code).gofmt -w, go build, go vet, go test ./<path>/..., and go build -tags integration ./<path>/... before finishing.© TheManticoreProject, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
SKILL.md and 1 other file in .claude/skills/dcerpc-interface-structure of TheManticoreProject/Manticore.
Open the folder on GitHubat commit 05af7a6
Dcerpc Interface Structure next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Dcerpc Interface Structure this skillTheManticoreProject/Manticore | 168 | — | ~7.8k | Automated safety check: Pass | MIT | |
| Translation Diff ExportDevolutions/UniGetUI | 26k | — | ~1.1k | Automated safety check: Pass | MIT | |
| Sync Translationssymfony/symfony | 31k | — | ~1.9k | Automated safety check: Pass | MIT | |
| Translation Diff ImportDevolutions/UniGetUI | 26k | — | ~750 | Automated safety check: Pass | MIT | |
| Translation Diff TranslateDevolutions/UniGetUI | 26k | — | ~934 | Automated safety check: Pass | MIT | |
| Generate Translationspayloadcms/payload | 45k | — | ~1.1k | Automated safety check: Pass | MIT |
Devolutions/UniGetUI
Compares UniGetUI JSON locale files against English, identifies untranslated or source-changed keys, and generates patch, reference, and handoff files for a target language.
symfony/symfony
Synchronize translation catalogs across maintained Symfony branches: find messages that newer branches added to the English catalogs but that are still missing from the oldest maintained branch…
Devolutions/UniGetUI
Merges translated key-value pairs from a UniGetUI JSON localization patch back into the full language file and validates the merged result.
Devolutions/UniGetUI
Translates a sparse UniGetUI JSON language patch, writes completed entries into the working copy, preserves placeholders and terminology, and prepares the patch for merge-back.
payloadcms/payload
A skill your agent uses when new translation keys are added to packages to generate new translations strings
Narcooo/inkos
Drives long-form fiction, scripts, storyboards, interactive films and long-document translation through InkOS, with every change made by a typed action.
TheManticoreProject/Manticore
Implement and organize SMB 1.0 (CIFS) message code in the Manticore project — command Request/Response structs, the command-casting dispatcher, reserved/obsolete command stubs, AndX…
Categories
Scaffold and organize DCE/RPC interface code in the Manticore project using the UUID-versioned directory layout (interfaces/<uuid/<major.<minor/ with structures/ and functions/ subpackages). Dcerpc Interface Structure is an agent skill from TheManticoreProject/Manticore.<minor/ with structures/ and functions/ subpackages).
Dcerpc Interface Structure fits situations like: creating a new RPC interface; adding a method (opnum); NDR structure to an existing one; splitting a monolithic interface file.
Run `npx skills add TheManticoreProject/Manticore --skill dcerpc-interface-structure -a claude-code`. Or copy the skill folder (.claude/skills/dcerpc-interface-structure in TheManticoreProject/Manticore) into .claude/skills/dcerpc-interface-structure in your project. Claude Code loads it when a task matches its description.
Run `npx skills add TheManticoreProject/Manticore --skill dcerpc-interface-structure -a codex`. Or copy the skill folder (.claude/skills/dcerpc-interface-structure in TheManticoreProject/Manticore) into .agents/skills/dcerpc-interface-structure in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add TheManticoreProject/Manticore --skill dcerpc-interface-structure -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/dcerpc-interface-structure, .gemini/skills/dcerpc-interface-structure, .github/skills/dcerpc-interface-structure and .opencode/skills/dcerpc-interface-structure in your project.
Going by SKILL.md and its folder, Dcerpc Interface Structure needs Python for the scripts in its folder and the command-line tools its instructions call (go and python3). Our summary lists: Python 3.
SKILL.md names 1 domain. In commands or code: learn.microsoft.com; the agent is likely to contact it when it follows the instructions. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Dcerpc Interface Structure is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 7.8k tokens (SKILL.md is roughly 31k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Dcerpc Interface Structure: Translation Diff Export (Devolutions/UniGetUI, 26k stars), Sync Translations (symfony/symfony, 31k stars), Translation Diff Import (Devolutions/UniGetUI, 26k stars) and Translation Diff Translate (Devolutions/UniGetUI, 26k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
TheManticoreProject (a GitHub organization) maintains it in TheManticoreProject/Manticore, which has 168 GitHub stars. The repository holds 2 skills in this directory. The repository was last updated on September 29, 2026.
Source: TheManticoreProject/Manticore on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.