{"id":2048,"date":"2026-07-18T06:47:55","date_gmt":"2026-07-18T13:47:55","guid":{"rendered":"http:\/\/macdaddy4sure.ai\/?p=2048"},"modified":"2026-07-18T06:47:55","modified_gmt":"2026-07-18T13:47:55","slug":"plugin-sdk","status":"publish","type":"post","link":"http:\/\/macdaddy4sure.ai\/index.php\/2026\/07\/18\/plugin-sdk\/","title":{"rendered":"Plugin SDK"},"content":{"rendered":"\n<p>How to write a plugin for _AugmentedIntelligence using the _IPlugin interface and the PLUGIN_REGISTER self-registration macro. This is the modern extension path \u2014 a plugin declares a <strong>manifest<\/strong>, an optional <strong>command schema<\/strong>, and the scopes it needs, and the host loads it with <strong>no hand-edits<\/strong> to SpeechCommands.cpp or RSIAgent.cpp.<\/p>\n\n\n\n<p><em>**Status.** The pure SDK core (`PluginCore.hpp`) is unit-tested (`tests\/suite_plugin.cpp`). Host glue is **wired**: `PluginManager::Init` at boot, `TryHandle` early in `SpeechCommands`, Lua registration from `AgentRuntime`, builtin plugins in `BuiltinPlugins.cpp`. See also [PluginBridges.md](PluginBridges.md) for the unified bridge manager.<\/em><\/p>\n\n\n\n<p>Related: Developer-Extensibility.md (Developer-Extensibility.md) covers the <em>legacy<\/em> module contract; this document covers the plugin SDK that supersedes it.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">1. Anatomy of a plugin<\/h2>\n\n\n\n<p>A plugin is a class implementing _IPlugin (from PluginManager.hpp):<\/p>\n\n\n\n<p><em>[cpp]<br><\/em>class _IPlugin<br>{<br>public:<br>&nbsp;&nbsp;&nbsp; virtual ~_IPlugin() {}<br>&nbsp;&nbsp;&nbsp; virtual plugincore::Manifest Manifest() const = 0;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \/\/ required: identity + capabilities<br>&nbsp;&nbsp;&nbsp; virtual vector&lt;plugincore::Command&gt; Commands() const { return {}; } \/\/ optional: declarative arg schema<br>&nbsp;&nbsp;&nbsp; virtual void Handle(const vector&lt;string&gt;&amp; command, size_t start_index) = 0; \/\/ required: do the work<br>&nbsp;&nbsp;&nbsp; virtual void RegisterLua(lua_State*) {}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \/\/ optional: expose Lua globals<br>&nbsp;&nbsp;&nbsp; virtual void OnLoad() {}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \/\/ optional lifecycle hook<br>&nbsp;&nbsp;&nbsp; virtual void OnUnload() {}<br>};<\/p>\n\n\n\n<p>You provide at minimum Manifest() and Handle().<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">2. Quick start \u2014 a minimal plugin<\/h2>\n\n\n\n<p><em>[cpp]<br><\/em>\/\/ GreetPlugin.cpp<br>#include &#8220;PluginManager.hpp&#8221;<br><br>using namespace std;<br><br>class _GreetPlugin : public _IPlugin<br>{<br>public:<br>&nbsp;&nbsp;&nbsp; plugincore::Manifest Manifest() const override<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \/\/ The key=value manifest format (parsed + validated by PluginCore).<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return plugincore::parseManifest(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8220;name=greet\\n&#8221;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8220;version=1.0.0\\n&#8221;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8220;min_host=11.0.0\\n&#8221;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8220;commands=greet\\n&#8221;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8220;scopes=\\n&#8221;);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \/\/ no host capabilities needed<br>&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp; vector&lt;plugincore::Command&gt; Commands() const override<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; plugincore::Command c;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c.verb = &#8220;greet&#8221;;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c.help = &#8220;greet someone by name&#8221;;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c.args = { { &#8220;name&#8221;, &#8220;string&#8221;, true, &#8220;who to greet&#8221; } };<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return { c };<br>&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp; void Handle(const vector&lt;string&gt;&amp; command, size_t) override<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \/\/ command[0] == &#8220;greet&#8221;; args follow.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; const string who = command.size() &gt; 1 ? command[1] : &#8220;world&#8221;;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cout &lt;&lt; &#8220;Hello, &#8221; &lt;&lt; who &lt;&lt; &#8220;!&#8221; &lt;&lt; endl;<br>&nbsp;&nbsp;&nbsp; }<br>};<br><br>\/\/ Self-register at startup. Second arg = the capability scopes to grant.<br>PLUGIN_REGISTER(_GreetPlugin, {});<\/p>\n\n\n\n<p>Add the file to the project (&lt;ClCompile&gt; in the vcxproj + filters), rebuild, and \u2014 once the SDK is wired into the host \u2014 typing greet Ada runs it. No dispatch or Lua-registration edits required.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">3. The manifest<\/h2>\n\n\n\n<p>Declares identity and requirements. Parsed from a simple key=value block (plugincore::parseManifest) \u2014 one key per line, # comments allowed:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>Key<\/strong><\/td><td><strong>Meaning<\/strong><\/td><td><strong>Example<\/strong><\/td><\/tr><tr><td>name<\/td><td>Unique plugin id (required)<\/td><td>media<\/td><\/tr><tr><td>version<\/td><td>Plugin semver (required)<\/td><td>1.2.0<\/td><\/tr><tr><td>min_host<\/td><td>Minimum host version it needs<\/td><td>11.0.0<\/td><\/tr><tr><td>commands<\/td><td>CSV of typed-command verbs it provides (required)<\/td><td>media,mv<\/td><\/tr><tr><td>scopes<\/td><td>CSV of capability scopes it requires<\/td><td>db.read,llm.invoke<\/td><\/tr><tr><td>deps<\/td><td>CSV of other plugin names it depends on<\/td><td>core<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>Validation (plugincore::validateManifest) rejects a manifest with no name, no\/invalid version, or no commands, and refuses to load if min_host exceeds the running host version. You may also construct the Manifest struct directly instead of parsing text.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">4. Command schema (optional but recommended)<\/h2>\n\n\n\n<p>Publishing a Command schema gets you <strong>argument validation, usage\/help text, and tab-completion for free<\/strong>, and feeds the NLU natural-language\u2192command mapping.<\/p>\n\n\n\n<p><em>[cpp]<br><\/em>struct Arg&nbsp;&nbsp;&nbsp;&nbsp; { string name; string type; bool required; string help; };<br>struct Command { string verb; string help; vector&lt;Arg&gt; args; };<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>type \u2208 string | int | float | bool \u2014 values are type-checked before your Handle runs.<\/li>\n\n\n\n<li>Required args must come before the host will dispatch; too many\/too few args produce a usage message instead of calling you.<\/li>\n<\/ul>\n\n\n\n<p><em>[cpp]<br><\/em>plugincore::Command c;<br>c.verb = &#8220;play&#8221;;<br>c.help = &#8220;play a title&#8221;;<br>c.args = { {&#8220;title&#8221;,&#8221;string&#8221;,true,&#8221;movie\/track title&#8221;},<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {&#8220;count&#8221;,&#8221;int&#8221;,false,&#8221;repeat N times&#8221;} };<br>\/\/ usageString(c) =&gt; &#8220;play &lt;title:string&gt; [count:int]&nbsp; &#8211; play a title&#8221;<\/p>\n\n\n\n<p>If you skip Commands(), your Handle still runs \u2014 you just parse command yourself and get no auto-validation.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">5. Capability scopes (security)<\/h2>\n\n\n\n<p>Every plugin is granted only the scopes passed to PLUGIN_REGISTER (or, for DLL plugins, its manifest scopes intersected with host policy). The host checks scopes before letting a plugin reach a protected service.<\/p>\n\n\n\n<p>Scope matching (plugincore::authorize):<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>Granted<\/strong><\/td><td><strong>Matches<\/strong><\/td><\/tr><tr><td>llm.invoke<\/td><td>exactly llm.invoke<\/td><\/tr><tr><td>net.*<\/td><td>any net.&lt;something&gt; (wildcard)<\/td><\/tr><tr><td>*<\/td><td>everything (super-scope \u2014 grant sparingly)<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p><em>[cpp]<br><\/em>PLUGIN_REGISTER(_MediaPlugin, { &#8220;db.read&#8221;, &#8220;llm.invoke&#8221; });&nbsp;&nbsp; \/\/ scoped<br>PLUGIN_REGISTER(_TrustedTool,&nbsp; { &#8220;*&#8221; });&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \/\/ full access<\/p>\n\n\n\n<p>Declare the same scopes in your manifest&#8217;s scopes= line so they&#8217;re visible in plugins info and enforced when calling the Host API.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">6. The Host API facade<\/h2>\n\n\n\n<p>Plugins reach host services through a stable facade (_PluginManager::Host()), rather than touching globals \u2014 this keeps plugins decoupled and testable:<\/p>\n\n\n\n<p><em>[cpp]<br><\/em>struct HostApi<br>{<br>&nbsp;&nbsp;&nbsp; function&lt;string(const string&amp; prompt, const string&amp; model)&gt; Llm;<br>&nbsp;&nbsp;&nbsp; function&lt;void(const string&amp; key, const string&amp; value)&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MemoryPut;<br>&nbsp;&nbsp;&nbsp; function&lt;string(const string&amp; key)&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MemoryGet;<br>&nbsp;&nbsp;&nbsp; function&lt;void(const string&amp; name, double v)&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Metric;<br>&nbsp;&nbsp;&nbsp; function&lt;bool(const string&amp; action_scope)&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; EthicsAllows;<br>&nbsp;&nbsp;&nbsp; string host_version;<br>};<br><br>\/\/ inside Handle():<br>auto&amp; host = _PluginManager::Host();<br>if (host.EthicsAllows(&#8220;actuate.write&#8221;)) {<br>&nbsp;&nbsp;&nbsp; string answer = host.Llm(&#8220;summarize: &#8221; + input, &#8220;gemma3:12b&#8221;);<br>&nbsp;&nbsp;&nbsp; host.MemoryPut(&#8220;last_summary&#8221;, answer);<br>}<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">7. Lifecycle &amp; runtime enforcement<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>OnLoad() \/ OnUnload() \u2014 set up \/ tear down state. Called on load, unload, and plugins reload.<\/li>\n\n\n\n<li>On every dispatch, _PluginManager::TryHandle wraps your Handle with:<\/li>\n\n\n\n<li><strong>kill-switch<\/strong> check (safe-mode blocks all plugin actuation),<\/li>\n\n\n\n<li><strong>rate limiting<\/strong> per plugin,<\/li>\n\n\n\n<li><strong>schema validation<\/strong> (if you published one),<\/li>\n\n\n\n<li><strong>timing + audit<\/strong> \u2014 invocation count, error count, latency, and a tamper-evident audit entry (reusing _KillSwitch \/ _RateLimiter \/ _Metrics \/ _AuditLog from NetFeatures).<\/li>\n<\/ul>\n\n\n\n<p>Exceptions thrown from Handle are caught and recorded as errors, not crashes.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">8. The plugins command<\/h2>\n\n\n\n<p>Runtime management (available once the SDK is wired in):<\/p>\n\n\n\n<p>plugins list&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # all plugins, on\/off, version, verbs, call\/error counts<br>plugins info &lt;name&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # scopes, deps, avg latency, error rate<br>plugins enable &lt;name&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # turn a plugin on<br>plugins disable &lt;name&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # turn it off (its verbs stop routing)<br>plugins reload &lt;name&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # OnUnload + OnLoad (state reset; DLL reload for dynamic)<br>plugins doctor&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # dependency load order + cycle \/ missing-dep report<br>plugins help &lt;verb&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # usage string from the command schema<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">9. Dynamic (out-of-tree) plugins<\/h2>\n\n\n\n<p>Ship a plugin as a DLL without the host source tree. Export a C entry point:<\/p>\n\n\n\n<p><em>[cpp]<br><\/em>extern &#8220;C&#8221; __declspec(dllexport) _IPlugin* ai_plugin_entry() { return new _MyPlugin(); }<\/p>\n\n\n\n<p>The host loads it with _PluginManager::LoadDynamic(&#8220;plugins\\\\mymod.dll&#8221;, err), reads its manifest, grants scopes per policy, and registers it. Unload \/ Reload manage the module handle. <em>(This path is written but depends on the full Windows\/MSVC build; treat it as the design contract until exercised.)<\/em><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">10. Testing your plugin<\/h2>\n\n\n\n<p>Follow the project&#8217;s tested-core convention:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Put pure logic in a header-only MyPluginCore.hpp (std-only) so it compiles under the g++ harness.<\/li>\n\n\n\n<li>Write tests\/suite_myplugin.cpp exercising that logic (see tests\/suite_plugin.cpp for the pattern).<\/li>\n\n\n\n<li>Add copies + a build\/run line to tests\/run_math_tests.ps1, and confirm it stays green.<\/li>\n<\/ol>\n\n\n\n<p>The SDK&#8217;s own core is validated this way \u2014 PluginCore (registry, manifests, semver, scopes, schema, dependency ordering, metrics) has 42 passing checks in the plugin core suite.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Enabling the SDK in the host<\/h2>\n\n\n\n<p>The SDK isn&#8217;t live until these three edits are made (kept out of this doc&#8217;s scope so you can decide the integration point):<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Build:<\/strong> add PluginCore.hpp, PluginManager.hpp, PluginManager.cpp to _AugmentedIntelligence.vcxproj (+ .filters).<\/li>\n\n\n\n<li><strong>Startup + dispatch:<\/strong> call _PluginManager::Init(&#8220;11.0.0&#8221;) during boot, and at the top of myCallback in SpeechCommands.cpp call if (_PluginManager::TryHandle(command)) return vector&lt;string>(); so plugin verbs are routed first.<\/li>\n\n\n\n<li><strong>Lua:<\/strong> add _PluginManager::RegisterLuaGlobals(L) to registerExtendedLuaGlobals in RSIAgent.cpp.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">API reference (essentials)<\/h2>\n\n\n\n<p><strong>`plugincore` (PluginCore.hpp) \u2014 pure, tested<\/strong><\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>Symbol<\/strong><\/td><td><strong>Purpose<\/strong><\/td><\/tr><tr><td>Version, parseVersion, compareVersion, hostSatisfies<\/td><td>semver<\/td><\/tr><tr><td>authorize, scopeMatches, firstMissingScope<\/td><td>capability scopes<\/td><\/tr><tr><td>Arg, Command, validateInvocation, usageString, completions<\/td><td>command schema<\/td><\/tr><tr><td>Manifest, parseManifest, validateManifest<\/td><td>plugin manifest<\/td><\/tr><tr><td>Registry<\/td><td>add\/enable\/route\/metrics\/loadOrder (dependency topo-sort)<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p><strong>`_IPlugin` \/ `_PluginManager` (PluginManager.hpp) \u2014 host glue<\/strong><\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>Symbol<\/strong><\/td><td><strong>Purpose<\/strong><\/td><\/tr><tr><td>PLUGIN_REGISTER(Type, {scopes})<\/td><td>self-registration at startup<\/td><\/tr><tr><td>_PluginManager::Init\/Shutdown\/GetStatus<\/td><td>lifecycle<\/td><\/tr><tr><td>_PluginManager::TryHandle(command)<\/td><td>scoped, audited dispatch<\/td><\/tr><tr><td>_PluginManager::LoadDynamic\/Unload\/Reload<\/td><td>dynamic DLL plugins<\/td><\/tr><tr><td>_PluginManager::Complete(prefix)<\/td><td>REPL autocomplete<\/td><\/tr><tr><td>_PluginManager::Host()<\/td><td>host-service facade<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Related documents<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Developer-Extensibility.md (Developer-Extensibility.md) \u2014 legacy module contract + mesh systems<\/li>\n\n\n\n<li>PluginCore.hpp \/ PluginManager.hpp \u2014 the SDK headers (source of truth)<\/li>\n\n\n\n<li>tests\/suite_plugin.cpp \u2014 worked examples of the core API<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>How to write a plugin for _AugmentedIntelligence using the _IPlugin interface and the PLUGIN_REGISTER self-registration macro. This is the modern extension path \u2014 a plugin declares a manifest, an optional command schema, and the scopes it needs, and the host loads it with no hand-edits to SpeechCommands.cpp or RSIAgent.cpp. **Status.** The pure SDK core (`PluginCore.hpp`) [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-2048","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"http:\/\/macdaddy4sure.ai\/index.php\/wp-json\/wp\/v2\/posts\/2048","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/macdaddy4sure.ai\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/macdaddy4sure.ai\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/macdaddy4sure.ai\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/macdaddy4sure.ai\/index.php\/wp-json\/wp\/v2\/comments?post=2048"}],"version-history":[{"count":1,"href":"http:\/\/macdaddy4sure.ai\/index.php\/wp-json\/wp\/v2\/posts\/2048\/revisions"}],"predecessor-version":[{"id":2049,"href":"http:\/\/macdaddy4sure.ai\/index.php\/wp-json\/wp\/v2\/posts\/2048\/revisions\/2049"}],"wp:attachment":[{"href":"http:\/\/macdaddy4sure.ai\/index.php\/wp-json\/wp\/v2\/media?parent=2048"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/macdaddy4sure.ai\/index.php\/wp-json\/wp\/v2\/categories?post=2048"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/macdaddy4sure.ai\/index.php\/wp-json\/wp\/v2\/tags?post=2048"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}