From a552a84dc893e833bfc6b17d359380d95793a2d3 Mon Sep 17 00:00:00 2001 From: Aryamanz29 Date: Mon, 25 May 2026 18:44:57 +0530 Subject: [PATCH 1/2] feat: add Codex plugin for Atlan MCP server (AICHAT-1113) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a Codex-format plugin that exposes Atlan's hosted MCP server (`https://mcp.atlan.com/mcp`) to both the OpenAI Codex desktop app and the Codex CLI, mirroring the existing Cursor and Claude Code plugins. Layout follows the official Codex plugin schema discovered by inspecting the bundled `openai-bundled` marketplace: - `codex-plugin/.codex-plugin/plugin.json` — plugin manifest with desktop-app metadata (displayName, brandColor, logo, capabilities, privacy/terms URLs). - `codex-plugin/.mcp.json` — MCP server registration bundled by the plugin (`type=http`, OAuth handled by Codex against the discovery endpoint). - `.agents/plugins/marketplace.json` — marketplace manifest at the repo root exposing the plugin as `atlan@atlan`. Uses the `source.source=local` shape matching OpenAI's bundled marketplaces; enables sideloading via `codex plugin marketplace add `. Verified locally on Codex CLI 0.133.0: - `codex plugin marketplace add` registers the marketplace - `codex plugin list` shows `atlan@atlan` as discoverable - `codex plugin add atlan@atlan` installs the plugin and appends `[mcp_servers.atlan]` to `~/.codex/config.toml` automatically Refs: https://linear.app/atlan-epd/issue/AICHAT-1113 --- .agents/plugins/marketplace.json | 20 +++++++ codex-plugin/.codex-plugin/plugin.json | 47 ++++++++++++++++ codex-plugin/.mcp.json | 8 +++ codex-plugin/README.md | 73 +++++++++++++++++++++++++ codex-plugin/assets/atlan-logo.png | Bin 0 -> 42873 bytes 5 files changed, 148 insertions(+) create mode 100644 .agents/plugins/marketplace.json create mode 100644 codex-plugin/.codex-plugin/plugin.json create mode 100644 codex-plugin/.mcp.json create mode 100644 codex-plugin/README.md create mode 100644 codex-plugin/assets/atlan-logo.png diff --git a/.agents/plugins/marketplace.json b/.agents/plugins/marketplace.json new file mode 100644 index 0000000..9e16d18 --- /dev/null +++ b/.agents/plugins/marketplace.json @@ -0,0 +1,20 @@ +{ + "name": "atlan", + "interface": { + "displayName": "Atlan" + }, + "plugins": [ + { + "name": "atlan", + "source": { + "source": "local", + "path": "./codex-plugin" + }, + "policy": { + "installation": "AVAILABLE", + "authentication": "ON_INSTALL" + }, + "category": "Data" + } + ] +} diff --git a/codex-plugin/.codex-plugin/plugin.json b/codex-plugin/.codex-plugin/plugin.json new file mode 100644 index 0000000..1a3936d --- /dev/null +++ b/codex-plugin/.codex-plugin/plugin.json @@ -0,0 +1,47 @@ +{ + "name": "atlan", + "version": "0.1.0", + "description": "Connect Codex to your Atlan data catalog. Search assets, traverse lineage, manage glossaries, define data quality rules, and govern metadata through natural language — backed by Atlan's hosted MCP server with OAuth.", + "author": { + "name": "Atlan", + "email": "engineering@atlan.com", + "url": "https://atlan.com" + }, + "homepage": "https://atlan.com", + "repository": "https://github.com/atlanhq/agent-toolkit", + "license": "Apache-2.0", + "keywords": [ + "atlan", + "mcp", + "data-catalog", + "data-governance", + "metadata", + "lineage", + "data-quality", + "semantic-search", + "glossary" + ], + "mcpServers": ".mcp.json", + "interface": { + "displayName": "Atlan", + "shortDescription": "The context layer for enterprise AI — search, govern, and reason about your data assets from inside Codex.", + "longDescription": "Atlan is the context layer for enterprise AI. This plugin connects OpenAI Codex to your organization's Atlan tenant via Atlan's hosted MCP server, giving the agent access to your full metadata graph — tables, columns, dashboards, glossaries, domains, lineage, and data quality rules. Use it to ground coding tasks in trusted organizational context: semantic search across assets, end-to-end lineage traversal, governed data definitions, SQL execution on connected sources, and curated metadata writes. Authentication is OAuth-based against `mcp.atlan.com` — no API keys to manage.", + "developerName": "Atlan", + "category": "data-tools", + "capabilities": [ + "Semantic search across assets", + "Upstream and downstream lineage traversal", + "Glossary, category, and term management", + "Data domain and data product creation", + "Data quality rule authoring", + "Asset metadata updates", + "SQL execution against connected sources" + ], + "websiteURL": "https://atlan.com", + "privacyPolicyURL": "https://atlan.com/privacy", + "termsOfServiceURL": "https://atlan.com/terms", + "defaultPrompt": "Find tables related to customer data in my Atlan catalog and summarize their lineage.", + "brandColor": "#0066FF", + "logo": "assets/atlan-logo.png" + } +} diff --git a/codex-plugin/.mcp.json b/codex-plugin/.mcp.json new file mode 100644 index 0000000..c3ad019 --- /dev/null +++ b/codex-plugin/.mcp.json @@ -0,0 +1,8 @@ +{ + "mcpServers": { + "atlan": { + "type": "http", + "url": "https://mcp.atlan.com/mcp" + } + } +} diff --git a/codex-plugin/README.md b/codex-plugin/README.md new file mode 100644 index 0000000..c0b54af --- /dev/null +++ b/codex-plugin/README.md @@ -0,0 +1,73 @@ +# Atlan Codex Plugin + +Connects Atlan's hosted MCP server (`https://mcp.atlan.com/mcp`) to [OpenAI Codex](https://github.com/openai/codex) — both the desktop app and the CLI. OAuth is handled by Codex against the MCP server's discovery endpoint on first tool call — no API key or environment variable required. + +## Install + +### From the official Codex Plugin Directory (when listed) + +Once accepted into OpenAI's curated Plugin Directory, install via **Codex.app → Plugins → search "Atlan" → Install**, or: + +```bash +codex plugin add atlan@openai-curated +``` + +### Sideload for local development + +The repository root ships a marketplace manifest at `.agents/plugins/marketplace.json` that exposes the plugin as `atlan@atlan`. + +```bash +# Register the marketplace (path = repo root containing .agents/plugins/marketplace.json) +codex plugin marketplace add /path/to/agent-toolkit + +# Install the plugin from that marketplace +codex plugin add atlan@atlan +``` + +Quit and relaunch **Codex.app** — the Atlan plugin appears under **Plugins → Manage** (enabled, with the bundled MCP server registered). + +### Direct MCP server install (CLI only, no plugin) + +If you only need the MCP server in the Codex CLI and don't care about the desktop-app plugin entry, run: + +```bash +codex mcp add atlan --url https://mcp.atlan.com/mcp +codex mcp login atlan +``` + +This appends `[mcp_servers.atlan]` to `~/.codex/config.toml` without going through the plugin system. + +## Verify + +```bash +codex plugin list | grep atlan # atlan@atlan installed, enabled +codex mcp list # atlan ✓ +``` + +Inside a Codex session, run `/mcp` to inspect connected servers, then ask anything Atlan-related — e.g. *"find all tables in the snowflake connection"*, *"trace lineage upstream from this asset"*. + +## Available tools + +The Atlan MCP server exposes search, discovery, lineage, glossary, data domain, data quality, and asset lifecycle tools. See the [main MCP server README](../modelcontextprotocol/README.md) for the full tool catalog and capability annotations. + +## Layout + +``` +agent-toolkit/ +├── .agents/ +│ └── plugins/ +│ └── marketplace.json # marketplace that exposes this plugin +└── codex-plugin/ + ├── .codex-plugin/ + │ └── plugin.json # plugin manifest (desktop-app metadata) + ├── .mcp.json # bundled MCP server registration + ├── assets/ + │ └── atlan-logo.png + └── README.md +``` + +## Related + +- [`cursor-plugin/`](../cursor-plugin/) — equivalent plugin for Cursor +- [`.claude-plugin/`](../.claude-plugin/) — equivalent plugin for Claude Code +- [`modelcontextprotocol/`](../modelcontextprotocol/) — the Atlan MCP server itself diff --git a/codex-plugin/assets/atlan-logo.png b/codex-plugin/assets/atlan-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..8086a46e8432cf3288ac2d47a50654048ee77729 GIT binary patch literal 42873 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 z zFUAl9FUGXk57*pM=%F+Mla5G8XS>D|&Z&mkTU23h9LtirA>O=z2mz;L==tjMw^w9) zQpsu{gRlTv{4~aSuATTMu6X7B?8@bVRa}3lru55<-U|Rog8*ebGTz)cP!9)i3z0B?dN z^NB<53IKr003ajIsjZYW;YEJR%|}NJ`Vhd~l$%uXhyasH+CN=BOHAwc9=4{quz=uwHwzZ^kP953j+~a^* zJD=w~^3=$}m%xlJ3F}8{AZriCKp-${P5DyQ? zzKk2fJ)(8C&|VAj6jkLv7(Cx^K-dWSVn&+#(@|lwxj@0hE>n|VMj@Q;Yv57 zm~$I=kTD6rS21YU=La!xE+6pg{aYGO8rb$wq%1|F7>nE`Os*!xd{u4WwkI_fPb4X2 z#xny0Dg>U}{W7mUxe2=F^VW`kEknyHPV%OD*r`-!$TA5q`a~@(uC-4K=t>J-Zlw}n zY7l(3yV2)d#d&^NJagsSV41&K2jL1;4|cdW1+)IVS!~&J;1ic?D0!cdy3>|4g`Yhg zm?X>~49Zc+f-{wg%fI|TDvg5Jhq?wB8e7Z}*9#XAbqY69f$r)O#%%R#x{gsa?O%Io zOB`khBHYYEq}#%pO_1Me-J>mrjRRF;GAJL1BTUXxdZ20!<~q0;yr54~Ncn7~v@ryO zv`x8>rhsQmC-X|$|M{nk{;iEYZ^u45Z$5mM2Zh!Euto3qOj!c8D!gL9+`1)K$r!nZ zLvKM?6qeu*_6*YYp4Cdl^V|pC#}WAPp>MtVys)*|J7a!Z51KwLYQegoLItqB6eZm| z`}1^1&f)_KB5iazxcmD|Z__J$D5qCT;i;e_WGM}d(XM%&OCH;Ug5}S_N92H=ET|qU zX4snLsfm>nsqvbe?607586^9Bc1Ph?L>gG!uX}b^bT3L{7tbbe4NwqJ$I7 z6lD69(S6HCu(c7|*2#j&HisI$6Hb3h4>&Wu&Np$gJTDNaLET&v_ss> zSH3nD`b9WoVAV-DkdEs}OOU@p0$y#mI&Hnq1L76=E^Mjkk~{ zWU^qk7QZBPQicX8f&_F2L=ViSPxY~n=ER+?7nO|5?tDi3$N86=AoahQMNE-^-VKdT zm(c7~&Pk#Ptp@gnncA?!8*Soqd3TTWIw}hP>P1?%%WSg$ zy&Hal22^}9K++prx{9PXM5Ri?n2!=s$TsEtchg_FJIYE>GlH<=KD@nb^?SQBr?#Z6 z%{{Q-#vj~Xfn-3~Zy?3O#o{aqc?XzN%K#JF!S%!&9}d#@rz9^b{?#mTYQE)E2igi< zekb59PM^B<0uOGwl_CuqTOWFY5A7lJ0X z?3El_&QY^q+(6RxW6Hwid6j_mWZWKQZhA^gF3!$@9$ zMVX;_KFyJ0Q6cvF3fF(vHnekjOc<7m@QNeUPPDWA3Q#tPKW1D67S z>Bm?1<*R-r=%johHn=DKAyz^PUGIRaG5QmCIceWm+d@s3aSfm*i2`OODk#y)h?hS9 zpaiZl&<7diyX0LhVm@na*S~qvA2p{3ga{%}SCiH+bcs3m9$DNGYrXEc z)Xae&^}vq4MY{l=f6OeYCOl_7gzKgGgXj_U&OrIcF0Ql`!}JgPvN>WU;;M%q{Cg$H z#&4kHjk9N-4z?5=Zu)T0?s760r~map&~qU73=}U4`pv;w@4#NnrF_JLqpSZGqoold zwFh$%i33Jzmz0n2JR%eS65w>{dxPiDs|3O22-k%MjeoyHd4n&1-;1`o8ZyAueU|Uv zOEc&}9(!fKmE26UGC3yq7{_b@$A;c{EPIEtpdKVgRf+<+yE)?5;{1};{SX;n00Ea8uaA3ZS_35-~-!cO{ny~E_^ zD}QwG2tHOBv&cO3_2w8+h)vIh$*Sc#O1Wc_nxqs_l!}lxztZ9A-}yYxvVH{U`#=*pJK$W#@JE6F-hwp)Hd>upZSSbt7U$u^P#$m$FUD$M=%3j! z#3S`-AinbgW1Qh1R8h z`uItA;tWeORhgk?#4_XMv? zAR+umvYfPl>{qX6<$Si@;;dC-T@?R?D&hj{2T!x->$x`RRqV36-3jvPe{V&N0f|5C z9H(BH1zz}`bSJfr&>zq6hu``DW3x>Ab@Xf!>amOSy3~mLzlRAhCE)bkS(}VGvjy7) z&(v_%kz?9~dI@vCtR*JAe)W#Zq&I7+!oMd`(IBCZ(P*8KANb;VUs3R{pE=SX&;u7= z+{>d&VGHlGxPRObWk4X<5V#%xIB8jS5SOuX=i2BWZ*hbx8Ub+Suv)Pq3)RG4lVU#2 zmmPczB;X&(;F_cNx>l;(0P*xnA4v8JUS}<59WeB}bY!Wv|zd>efFZ_?wv)DGNXy^g`lq%q~vHnYalcpUHNqA^wINh?hAN z*mX>&K+hk)G3fE3$OkiFc&lw@?_@a%mX`A2eum=+H-Luh z;_cD3kte&UNsG59f{wF4AAmKwoaF3qFzi4j>sZ4J74rX+0n!nWGq`=3&h#%oR_ar3 zI3M?-gfLFPkBxIb05@o^C85^O-Ld#ru~68{;DY;QrDe&r`*V{~kB3Udb3~7$e$@4P zG}WG#B-q;NO__5vl=%mK7btzoF8y4;;yqn4u+HrAAF@uK$6_^Qic*s_WfUi%+TtJU zVH8~~%yaCX}XVwQ(6$6#ef_VjwlL&5i2^F+mf z3vYT<&@oLTz*qrf&ShpvA6$&(&_2iYPYQCREy!DdhO>#6y_`1m&VENc`p=!f`e{_Z z_`WTgwWetbqCAGpTnxbUv4dd5oEitU=y5?}C4ihGZcIN-jiAB$93$MDAJ8rG0OSiY zD!<(l2uzP6^&eJt*+ZQCVa)pF#_0STpOItH3hL$!RkO>RpVDE~pKYIcNNzs-N6-JD zI%k9@b3DZa=4nffPPvEM$4mrdRhIzi_Mh^7hAiH?zOlCXXP)=x0{lr>9IJD{``-LG z=7Rbeo@2-&s)W$N8xNkJ^e_8XE^nfF3|EmW09W;M@4uCE+m0NgT!fiWJ!0ruX=a0? z+WaxuV4j1Xh$F|BIOg{Od8Ef+DDz^mj*`=H%o0aA{QtPC%#Ut%?S2aY+`YYc9Po8Q zu@Z8g(d&~ZT`y_=PYVO^bAU+lhj4*QP6$2Rao$K$6;74EjSS3e&}_DgKQ7w)&{e*a z;0VF3nBzx0L6d!#xhYF-W;-TDCs-<}Y|`%-&Y%tkU0a``&Y#O>`$LUI*mnKeFKovz zKo*98utb-y{w~ECPS;WyZ!+Wfp9|i|gY@LYL?}Ed+E z83dp-f#N^lXr0vVtL}Mt95rNN1pq=`x2>#mr@XWw|F|~>I{Ff1hx`hI2sa<%VPR@b~`I@P8dCC%qS1Tp68kKbz zD82qPIsSg10yr%EN;q=a^mp0ju|pu}NdcBz-dMBrZYlKW7&3!e*Z-3=CIXN#%Z(S6 z`8!MaA3!ybXLYL9H7_{$H5i-y*F#(d+%Mp^sG*7-80fpX_ot!o2Poz@^xdqL`<^SG z;=xX<-+#fCK;KST%1R|Y9xAAsI+`8+j{&Mck$3GZLMEjO4(5)#LEyLcjdV0oiDUve({^HRpY`W7I)&Sw36K2rwb`apint{3BaE=)Whyn8H{s zcDi~N`JbGM0ON-UtHHJd2Pu`6&Caf;dt5U>qwxzvNl`*6ZY4JjF?L*nSYB9$kZpU% z#?+1T8pq|H%pvkKuyK`cQ zP1CvkAIw-WU+7A zCpfdTkK=xkQ{)|!5f0bx8&dLbxdp6{0w7tS8GK7}$_A@cvH@+YOscNWUaC^m|ry_qc>?P0_!^N~~>+4>f)q^?Clm zI3GdgAKbg(z|YQ=attyG>xhx>?3&qrloIt~*D>Q~!Y(^Iikf!+*cD zRYOM+0b=81Wj-9sB?C}TV2=azWS~xB6(UbB3pAg|G;FOzmt6-=zS_f#nATN!K-27m@Ok+AwP-%ZOc90u|_$4{=8Yu9l1ZA zp%Z4v{zxt{<>A-H{`#Yomz+evTKlx+$IXWVds#&;;Y2?d3eW5G2@0@;l|9d5cC4lskK*7d+Rj^rHw}GU4ae? zMLj>77RjM2iEI&>=xPBXUWzX^2kSk}X~G9hV_q(ttj^PG77|GeA69%GFOee0AX%Xb z;5(NUcQ@*I<8H10yw76*Zp`D?k#RO^FZZJXNLHEzAM+p_I{Fl=FVkms7x}WlMLxJ_M*E4&9$P?fq+Dxnw4mg~j~8;kh{HV>cf#^upS*ygMh&y%e-M_s=K zNvx|sPZ-oh&P8z5Lj2QH%eDs*Lnjxn>-%kT?N`Z`29gEF>>!4A;tW7FL8SE^zK?p^ce8#9_=-g zVM7ekHIT=}=)=FJr9ZgY$^T?%4kvr2pD2z2z*q6b6VJK4`RbD8?2R>+t{m9#F+!teK=*lFUcJO1Qprf`)3jUQQ0a$#v?xOy4L3hmUI8p~ z@DA*D%hl}Gw5P`Xx~EnE&&lx5^7mafN(hRaxIXpBj7S)=M6kbz90@EV6MxvxR|-1P z0VrCXrX9vGRkUt@&92{iE6d}>r_|1G0GUR}X70w0RJL`SuV5eLjUxW*#1-1oFZVIq zGtqZkJD{Vus{xhkTl1KEo_UAGNqtOs}82GPu;t6h2R8$ zg-5`@n%ql%Tus%_auzWDCyh>1ug%-ckHpD-4SKhw%Hb@Ogs=>HRi|cGzx~^#OyA-& zIzm1IUZC${wj$Rq>{{*2dMpb+3?(HFGXaxT%?A;SPvXu-?mdFWbz~@HJ9i^H8LAhm zue(a{x`=7s?{{5qhz?yW-FU(S#zj6wSi#ZAL-L2BB}Gh7$G?Fm>Kj>pJGNnCMGOol zduhwrd2rfUkI1+4F=kK zjyU$o?F-xa_pNTUJTur4a#;;c--IGqy1=qQ@bG3>NE(na@$1rau{fK?jco`}9E~K2 z;r39u#%h*@`(+V*DuY|tLCN!b)#aDXTWWu{zk>ogrUM>rc+a82)h3OQjRqN2jH0h0 z@lShrF=aHYvu)=r3QLaJzA$A$E%Bz!spLzVEM%oPW*W! z^sjcP*Dw4kw!eCp^k!>RE*;fvYT1xn&aAsC{8x@F3Yo&)7}K`YFnJ)r3=)G*qLziV z?WKCKEBb4X+aJuUYVf{H#UoKePx?3k^YkcHEt*}yN`)}(bRYlcMaVCa>3|V^itp6r z0m7`_C~skO_nXn|E&?#1evLX0)MT|zeutSB9FC(C;jhe#okzHxMVFP)xTioCa~*Rr zVzGH*zOoO!1<-xrFyEA1{kYe4y2(ShT zr1G;w68-pr2m20fhqpJ{W5EsvPt!L>tJC4}7`7#4xf>t7sx97VB zu%Z(ieU=`UMA~+kbl~GECab@@J(GX;Xd6V2YHovR@T`GT)wMDc^#GJMQBHVT@n$wK zWLzo*3Tz*loE1qKl?JF+4?)t4*Ndcs7Tlnm?+QQ2o0eB4WyMMaxeOV=WR6cqP}I+8 z*saXr$>pv~7l`hN;lJDoFV>;a3vVQ-mdi>PC4ml~DD6m*i$=YlncSme}Q2XS+V&e`_y~kn0P` zJF%HP0bWNL8xz=jZ}N+84OuL{A6{c1Ej+K9TEso-No>L;vcEBNyD4N-M&IXoG*r)m zT}=t1{ON}IJFQ?(lS_ayEq=eda+kN2j3(lSE#Lr$j*LEw$CcU{+ccry>uLe`C?X?a zTS194tBuY5h_LJ9e6im%wu?XMQjCE~s(}*PuSAf%DMnDgovUNr_Qc@cS~S^)A&WprD?&#zV_ZM3$B=$XTxT^gYxD9DhNS z)Bb8k3i)I!^a8XCf-EdXRT4Q;$r@Z%fWRS{F!fpu%|V=$AW`8E5w=UyYupJcI4O#J z1SLPAutoZkkM}0&@8^PTPdmCdAp@IBy@RhCz)db^b@F!-4pv6Yuk<#m1Oj2^5|`+8 z&GfPBwT64>k#_a~c&hR!(If@>&nPq*EMlEWF)sW$0p<#k5x=cvR~$=U;$=rFWLHFh zm^B!og9T_|IDM{s@~vIiX9;k)9EGh86vqv31xkAY3#TQ@vFK&OowHWffS(k`zG3qX zAqRuSmvEzVK-E=zR?1VWvJx&q>rz=n5udnx%z>-NZ4gtItDKlE@}1}DX?MTLO$!- zYOj7@eQzkuy9WyyoK7}T3cyPeF+)Yl^1asZ#_jJH>|kJm(FP_MpSVSM2$dESiXHPn z)_bUDpr-OBPnJb_R&$&mU%y#iI`4 zIU`|oxc%0or^I18C|#*fuUWtj7X!&fqoV@0eAsjO6QT+S(iXanrN*BMVS3m+UI^G;Y`vnMPBG6cND~v>p7Y zt~|jK3l=v-6fi&1#wytqw(Aj3oFKJKAiW5*0+gSueUmqo15o#1cQz_4#4GY39oB@W z(%;hcDOaO`MrbH=B4&PDMcsvUIwjDICcB9wHP<}cTiZG<2PrRO1RfMjeA0rWrwuQ& zb-W3KR%lv@FY0$$4+zJRe!K;qu~kGKC@wGKA_wQx*rC6T0q)izgJmP@DgmfXSU4@z z`ly)n{-FI1?74ahQHBnvtsLyJ`*xbILJM9ec|;!i-e)cgHE+1hM($u64C&K-BIa|p zijt#J?^T?E)nH9A8D65s`-+{A5}gz}@ln}rn&oNmb2+G6CwoI!l{ z?{Bve{5u-ad4m7F(s_Dft)wwWWvb?-PK`AON2Pn@-1BkKJ4$fyO;sy9@CVYfQIC$rJHU;Xj3K6*oRU-6I1p zRZPKWq?m^&xhtw5=?KBiSZ6I~Cxy0vvjjcMb%v5V{q`JArU2`40YWL}w9E;hFUnx~ zpV67xf%?)rs$omk=>6xy7`sR z8x}J}c7nEbdF4I6O-E+M1k_{OSHDwibQP>+z!5>{7``+xD+}h+ah8{A9%VTjEeiHL zKcFtBfQbG6M&xy9?muUOOnPV)^QHrbB!Kpo-sEH3*G@?Rmr%`Y*?p8@P$oFT)(@x| zK0sQN!H^&q_gqt!Sq2WCKgp?MEYI@JX^~vH9tAFoL?wDTmB|fIgG!zl0WG2 zre;k8Qzu}LzD^q;#<4B@A`1g}Xp(xSmK}{Fx&l#x5Z6r4D0pQ&_Iv;(m)FpKqXJ+x z2AH5ZeywDFr~>T#xxwv#F1qF=X!2&C}~>xj)aP@Lnf?H*n~%eG%KWVzs<< z4S+4-gwhL=p?cw=ADU2E`9>c-8R+hJkT+{H-yYHnvU_7Zm5fcL=L>Kx3yB7Bk8^x! zbq_%x=USljUGIc$c6I&N|&4SKydeA1oTxi1EfuLYoLp}USI`S>p2($eZPe6ti;;#L570Zco|;03V!lGpj@ z3#F>kIG={KIJX)%%LD)x3+w*To)M*)V;Tv~(2$0h(jyz!t6$J6=A>af+U}Jz7x0*0 zp$yUjDna;19b>0wPcVjneuIb(bV9_dOhSjI4%7fQF!!#2%Em*ATz(b^4EgK&czHRC zzohqe;4=6#DgwVlpq7YNfF>kN zJdj!SEIC+?#gJGfw(p#LX;gQ%%LaN7%ojx4Ri@|~`I~&TZ>n#T zgS;Po0<%ssSUfz0)qW3^0hb6_VoFb?YfO z;+v3;QG;IP+moOK?Fzt8s9tK^x`@hEgNitV0<54TqBQG0&~{Hnq*U_3_QJ&Q4Pd5@J^l zevdH?c=y4#Ao)iAdI=tNWZE#ZuZsj<8<^r37JgbUL6GfWiKahqs6X>WglVEP1I59j zri3_hk{gAkBE;ds3+-Y7&_$AjOvgTBXYd-!xx(upDfzU9b7uB_415_;TgSWeGu{xZ z`O$IWBg0R_K%HKu&up1k{r>Cv(c2hFFl!rVQHlV5ub zYvzCOqJB*ZmnZFgu(q+W@jD+hI&J!j846_lJJUeQrPKa(#u+SNpHZJz{P0;7tYqcV zm2iZLl}wLQl7Xm050EH(nxFdt?j(24oiDqA z?GkUnR(#2wig+Uf@ZuEMI2S%tHnqqD@5ST{a3`B61mG)Rpu+Or%(y?cei8$R=Op%K zH{z<*OkUiyzTr&{3I=nH+px!#5OXOY z;L6-Oe#O7Z91n2Llg{aBhZ|luubl){oGD=6eDpW1a9Hhj>x!9ftVFTHYUl-_#4xd} zo-lj996Gf%^U18W%Ha#2apSY!t$aj#C2>-rVwJeN$sc6|S|?7&sJU+~ANIX?#O!rZ z3GGFQD`_>Zh$g@c!sAlYp@CFm?Z|RZFD@8FoTPw(fucLoUsgJ7&}nDJLWmYl74e1D z=8><##J{-o5%bGtuuxc3@9yT}@=u7B&r^P|F$EXSw^T$DVAkP!3F+jxE#vQ760f0* zB##^I?k*@U(Zi|J{wdgERi5fozT}CdCnC=xcYC_s1M@%I_|)Yy_T}51-0U0cq?jBV zJvGp~5bD1xS8#@hu^=j#3mxaKI&hI5R!wQ}L1CTcz1h@_DEM_c5ve3Q>yxZ~t!K-I zBkNcP1r}Z=wr05=zAd1AZ@*gMc#iPU+9aeItigXf3mEGw@3a5?Fzn&ZDS5$P%p4*Y zFwF~tzgOCSG$}ilvmtI)QXS5^uej<38L!Q1N%Hq~R%sMjozeJ@ZU%rvi^>`L>+ z?lC@o|CzySP+{q#n*-fzIBtsjbd6y`KvSRtUc9;qT4?(FlMM`*26)aue>uxaO8GbU zf+DSx!!EwB=KO{Yev-0WBbRIzJS|9H%A;T;-p7V+u6AhskZJpDi|=99raJC4N{B_b!}J6z+A9N|kkgL}any1stB_ug6GNPhrRq!Ezf|X4(y^jx(PP$F-pb8p`A40 zx#Otki!&j`Rr_w&eNEe=3+|=aH}Z?5Www9%=t&d?L?#XwGQYRiyAdu9`*I32i)a$s z1SHNFTpMETC^)>Z+y8Y!ygq)>zKHg+)0y=t{lgUp|A9&q2@6bH1}|qvO*)OO()em% z8J|qXw`=F!6wo@b%@irAH@;=!2|u?|%>Ctjbm*sTif;HHmhjZtsT36o)>Y>euKO-3 zC5tco^S=Oc+$TTy?QG4SS}7{6a}6J~1sU%R=vslzK{8cP#gL)U(GNufbQu*wVLhu8 z=KhBZX1Z49@n`Pe)%ELs*COr2y8gLAH|Yw+!NJ&Rzo3(<0Vo?-JVObM6st!Z8yn4B zCTf_>?to?6?4FXEpwfjpWR zVPe)5m&k2S%ykU`_vRdblREl3XC9TCnd54`Y~LDM*>Tl$UpS5Pq@T z`F%>4wl!k+h4>fhxySf=qI|XppXXQQsa2J+ZA-i~p{Qt@H|`<_oocuB#4Fk^GIXsC z4ElSm{#L$UZCfD+%QPH3;8K4L$Z~O&x6f`K<+_fAe*o`<%kP6;`-ezH_&JijpTan) z9*TyQtqAG*twKHKN%hOtp;hf?(vZoyykhwt}9gv3feOa2geKxdMuFJ*GL(~L7VRl<%@ z5FMBeM^>{xV8pxw@9QPtD~Ocz zrGtr+6OW}x5*)5X*`AH!q-{};Yd7O^p z!SA}>h1RXGsWap-eqsUf&<~zx*Yt_unKDma96X2I&+jSAKA*KQj2$h}W36kvB38ogFM0w0o$0GR zEc8yJ_!IB&dXNs~opbS%mvXi0e3|9MDI!D&dNMDT`;?98a6RuzGw-*W$E-}|z#ita z=`r=fs8*lOxry z+`E3rFeTqX9=%T6JB^v(7eutB{4wh* z!D{YZjfG&Ki!y@Q(3eCksPU`4;)u!uMX#R^&gjC7{Z&}V02O!TS~_@jLtDO^a8Gjg zyu0f+H;F;;E@(e&mbN7I3A6iPcm#?ZHa)d@spQqOGhl(FBv5bwn{ zyG=`#9j@4@K}AU7iN#2JhNDEV7YPE zFu2;4pYdTIu(E{6`I%Vv+p!xAMU|xjX>)V0o2|2BP6w06qk!WL>cm zV)d|kPv1Xrg!qnEWx-0Qj{!_+PvGF^ZnkV>-8Fl}<2#Lt>Tg#d*BlNd$x-i_0zj!b zmyYjUz&_C>^-{u^AKuw;-Fq@KLg#${GT7weNjsQnUNNgnv8~a>3`94jT*h?N4(NG=^MX;7Q`=2OkLPI?8_p6>m1UmX0M9z~97WvVKCE=%GnQJz}DnDoGdhX+tL@W9_=agjJ zF#}ff>Yd#b6E|E$p6W8fp;<$fVV8GsSr2?J3@j1w#5^*q=kL!Xir`(T8W^t_$oy!M zkbp{bcBWeqTgdH$C7Qq7xZ)qk+w~m(Hc%XFP`J@PaU!OidlWEhvm2H9!ZNQTNl>xh zd|O$9QdJep*E&?|x4NLGz(IWH7GdX?KSj?g=&VV_%Nt-Yj8BB6rpd%)E(>3AE?Z`z zJ76n8_3phl zpNP4gNpSU^VX&Suis^s1HI1~Z_dTdIB`H254A(xL{ z`o_v&$~nIM9@O>O|MB)5re0ac&vhWSz&(bpKT#ufTS=?<$7N0t7R40I1UC%cLE{N5 zt1uZHvlqES$CwIVq36gISo|CVBi~`Mx3pOg#9ff+;A0`F|B- z1zS=MC=@~K;v$bua9zV-uZum57l+GV&*lVgd@Zm#-|CFq{TUum>*F1B9z#86G=4`u zX@KkXywzM9c;zAyynpjqfbGS=K;~N$Ni?RIY}fkkZtVD1SJ#Kv;z8!Z2f>ih@40=( zO%rK~;m6(m@bQ@g6Gl?(fpg-#i6VLqc3?cG8_YXUqVk0Vw0WGykH_Ko(G_kNVX2vmx;Z$JMconw(8A!v#1rLnH?n1--ovTs3tO!| zHCISqlwvV=nhJ3x*&C@S*;n;7JVJ66e?rMDT z;kVE>7IEVH!_M28b~|d+9GE4dnLmmnOG^b>Yso<0&^O*pMHic(?lf)0Rerq%oL|&K z>E7p?*26eK|5NKchA{4~6ud>SyZeLeN=h&wM7@HkbpN;{R`QHz_En+Z`qY3Q;*Q^! zOQW19El}o1k%nL`9&L zm^S9wEG$0b9v!9v?+`tr@Vqc!a*|prq6;jG{qhYK*XCr^1^fuZzfRx*$$K1qA=9_7 zH-)%d&Z3|B4YCvEKK|MfIfrlq12x-9ke!2O6OWE{_csOV&U%>mqYwR!mGBO#!pq+- zi#)56*5snN4Q_jbUkeo1z9@SeM4}e~V&L^%^U5&?e&524b|)?o3ycN-uFK~-ZJ#-s zS`$qv`B$7>)p#}eq$ye?r1pvmlr5zrV~y6!(udQ+V{ckN=I^T!l80^S-CvquRP*U@AeI$)s9 z3HYV19ud?06bvblg|F~jZPHSeuM%5{lR3}>D@=T9Ra5bKYOm!fK|jS)R$|y+Iu8weiH7j83>2|e@%j>L*53AGt;@HO~CQmHYF+MGdz`{S zr{KrBq03s@%MMoS3P#TKx3mqRTPcDSO@_o~Tnk*eA6^J6lk+j8R5Akok9Q~<0P5Ic z!m{$z^`PJV=Z!cDL+V<0VlsCI@Rthbz0Osg>Q#9ug_5HPCd~VMJTO+>ltn$PuBSL% z5C26e9ZUuLSnY8(n)s{lhJ%9~r=Xrwj{%Br^x{e(T8|=Lcep$Hm%@;{uN&J%QA#mm z=EOI5cM^xK4RMQiug!cHXK!c2Dswj{GuHEJB5r9h^2OZLC=@mjeHjQPpYnTWKSYnO zd>xcGIfZ(KbM+k+yJjDYj-y2oWQIF7+HNe1f?<|hTe3x@-ae5s%y${*=sFNtwIech z(c>&;U+BOUn2dQP{7F&N>L6$Pv$~!oSmykm#)I9()Ab8pfL=HQIQWJnA5+-A%Te;W z^D83mSjs6ZMwiCp_&X{DqNO0H4#@E->H{z;I7?IvU$M1Hn+xZlFL5l(z>M~XXW$}- zXn0F|imL|CV;a3g?q6mne+R)Ynyn72!cW3N5OU*yqghk@Xds3ks1SN| ziMD3DpS#xo;wazwV61ASxy=WVh$zHn|XZwLL-XWKJgfJ~G&y zsHYPjGi5+j<^;BAaYXN25#r&;*h6*j+`hQz zIdsd(JuASKG}e6G_=m%FFZczsdI1LD)+-{}5E+Fq+_kz#QYt@e66>xIDE@v^vd92+ z1#hPucsoBJaKE3>T`7*^3@BHUHOIU^`ffM^ph6wYN?>oljeRq@bX)Y|gPq_@i$Jbh6(*C0APKWM*8Pxuii`IxHX$)=d4MkdEk`$4P;}A$0e{@B zNYyYnE$kfAHbu6UdIaKbvw+Wh#w7sq6BC1~FXnSB^05bFR1Y`kGXK;1k$^A0wQA}{ zDmX>tOeii_o%+po;~9H<3h3rAI~Isa<*^I#@c9`Kx74FWD7o)(G$ayNBH^LWBtXpS z(Vl@%X6e@1X&|3)dWD&OqC|Vp13~=^0oD3XPz|Zo!xDdER@ao2XC-G}{A4Hc$5g@) z+_}wm7R5l~Zj>#zMOr0r&(uo*z03*t49a+&RjD`6Pm*IdfG4t|YlGOCPz+tXza_Bh ztgHh?uzW;VOc4}fcAZTK3TbIUxn&g~Rt@YHvrLpEmPu)`7FG>U-P1Y$)jNUi_(KZ0 z!va$TvC=%*;2#Ki94C(rnK0zHnL)&M&;k^VE$v1h#-&iEATbuXO=+?P`^w_LVzFkl zyM43@pWjth$^htGVJw6zY<;F7qA?7_8?Ps42|y0Pg`hz@eCyyJK@nIjSAckPg>-}* zw8d~O8Ev&ImM$p8Px9={NSlzoPZ8P?`PCID!dO>yXwlk?`0v;MvfzX+!P{iTHdg`Z z)^}E}iYILojL=|=uCMgNM|22R>pv;KKb`cak^j)qK^x5#n`fEQX<+#IFV&16b^-lE z;K(*2Y6%Ds>Az&|5@Y9p7E!{su+iOX$pLLbAv*Z1$u(8wM8Id9`YHtezB+f_r8v%Hx;Oz#hjwH+2ZBnO?uf>myOSCUpH zyhnj{C8eSyv>(dA|HGB?-$~9u3U`f?j#&?0ybU5O*1lH2gUae}zunp-VClJM4 zJPE$%kIh10@w4osVj)?Lr z1iRI)*}HER&VGZAN5CIOFr+mCW0oj%22lrfh2Lj8jmm!V{&sW`->GBvS3e?HkTe*~ zpg4_jh#sKIB5V4;3S52=`3z$!oT2z0yf@=yW3mEO*v6LBtsFpfX_Nfe+wD7mRh*qSRw z-PjlT?0Bstih7ZoUmSICTl=B5c7dD;1m(%jTu4o_+o;NXT$b)loyOpe!P-Zas<$=f z?=S@HfXt#kb89>Pt>7G0NF-(kwX@VNzHYjZx1g6z)6^>Z?xjj2k`{%&+R>LvyP(VXcmvmJuJ3`A0E+SZe{e5 z?t6QJ4&rm*V8&3qBm-J7yDS~LgF1K;E`X zVb01_4wmM0Ab&+NM5sw2GQWtXXN1+YJal*+R#&DJw%@KfdVIBF<@{OXGWfPJFlpZD z+?B{qmB>c0alt_tAsLJy-gt>WM5JY~^wHUHoTsJKxmFjbenqy_S@&swR^d@gACS?* z@L46l>KWf6hHsIR#@<{FB0oOTPJEuzMA^@@Bu6xCE7kR1ZU{PN@u$Kxo{0G?1@W5dO=a)@Zl;PjTrQd3LA{RoQ{ z1o=U?bi*bIu#}vmifzV6*`EZ;fJDS>rm#px_94O~#R2C03`H(7ZAl%6B(0vGCGW_O z0uYs zN{Yh0=9`YjK>Bmy$Cz=Hxscp|n2Qg?hjA}HiTtSRSJZ1S0TQw=ATjIQ?9FGa*$7>bps8>XUJyeK z0ZN7vD=(w3_p&F(n>YsJg>q!zu^Q+cuHb5p6y@v!rAdp_D9<&XV;2)Acmg>9-`7DY z_B4%uH^In?bq`N+Yepe+d&b)wZZO)Mw+~`p`wvA>ZZVsIFGz@2mi6ItFmv~mNr;JJ zQw%RNlk&o}UAk-_z$rxASmabF)^0Dy_&J8&0 z7-Wi0C(I~vnVieIe|^3&<$es?dDJvAY4S1=RTnl^5GO+@1+DkU>Y7j@L3$vj%SP2` z@uI)q?57b_MMMDcCzLSky+;tT4_@{Yv~57 zpmE>tDqSEDEe2=9@M~SXg9}a@B)P;YxrPP}DEb%j?MI@XtnJP`5%chRj(XbPUve&W z!n%PAj)Q9y?z-*bVInWy1V6x>M7sBHz1Ks8vg>3i?F>>H*1$OXzQvK=Vd!I3G-Hgck!|eeMb5XAt(3*El76`uRD5j zxdNCW+fvDUjyOKqzRmMq3g@arAEqr2t-u2wvQnNdZs`MuRK8v#kYF&r9J@hiVST;r z;hG*fREOl}$K=@2k00%=;275+2LBeG%0~04s1B-`q;J|?H`}b>+?7N-8+1Fm@bR~^b%R))na2s|`-)pE=XRjfj`%+k&KeSN_+>KVIyed|M6M zGB1}x!hkwg+~4DvXr-Nal*p`K@T3(YRdB@MtGtXv@^CJRo;)bYIJl#GDBLSw;0#Fx zsuMYj-$~DRUI`06Nx>bq{B!NddP&-MVf}J&cmAO1X2fa`z2UZ+OfT(R;*NHB2qB=x zfRTiP@VM_scirZG+&t0L))}s!t%l z#KPRNLPP|>$bl2}Ty4p`K-gT>8CG7Gj>}eu&6GVL7~(4dX(+1pkg#IDa5$lv75Ip}35 z!ful7ELZqh1QEcoEjtX-MM7rC*X(AT8t(~<0I`LPJNbA8)~Kj_XCB|(#wVpJB8Add zuDdq=xZ+x61^4PTaMZ!I?F#fw)k@b9``TqLJ&-G$MK&7|i7sskl=JkGpq!JIr3Bv7 z`YOEm(Td(t>?djG#|T%9Ngap`T{lwJS0_&nV=TQ z&jUx*q?@o21#f+GlM`Eg;RldRmIiUy*yH2c!67P z-GeuI`aUKP)&Fa_l(*d0{+ekXagwBTRi|DMaCiX@=15Z_BO_74M^6TKyq5MJ%cllc ze*1b(xX~27|AwL@gFAC%=&j|Qbw@8Q4+4oPu2fb63MIp@p8;i2t0rZ&1Scfu+U>O7 zqfcJRAOA>bQO|x+ZH7DbW16da6o$rEVkECBrKhAL1hXo`HS{C)0QM~rgqsr57_Pb; zy^mo-wQ+hyl;nJ2N5331xfYAyx*^|z{CdcwMW^bQYhNz-x$$rUFvqC|0&#O6RG&=V z_JHVL1%3WV#_=svbtyIa(6RD^Oc|pqx&UF{p2t6~@?i|b)HD~ z#5_GJ(^Gth7W;|_sKPtnFW|||1~@g?lw1}9>B9Oeh&5fiG#6xP7ZXwa-)J3crXbQv zl*_rOATz^=Ct0>IPaujN13l)VSpPtP;YXv98xF0pd+BSVB`Z3(gF4{JSv8U)mN zze7;*$+!zOgjR^&XtcK$xYEoKnhk@>o!Nttmr>tL)j!|okCfNwie#VobnG1OJH_7x zhEi8WFxWh9r#IzeM+JcG1feub+7dVMig{To<$b$GrqN zPWBPr(4Y_fDwc|!5S|`w3Da%($)21p93XKa-_kNde+Yzru%gIo$?}_rVrdb-Q{9qO z0XBTRVZ?BthA9jm_3?~e`m84A%m9yHdNS=qP()dQGaN%4PHr+11LCJ12fPL8*T_26 zisgIe4Ks}^TOg#_M%fp%NL}pH*s*cO;-=$v;t)dJ=tTObK`k>=@FyaK)k@YFFcjHl za^n3JU}%`VPCs+nLL$I1a{vMV6PY*u0b_^D0FuB>yxN26u<`aD5kY{W;xQbP0+n@M z?}4g=caIGniV8{`TUE@6w;y@4!k9W&KK$Ys?6xI!PYLI4eP}&(>dyD0kr*kI#Asga zP*x^S-Y*TD_+|4~o3ComZN%3;zZKbLu{)n|6c^p3O!?M~lGiK2shbmSG6w4HG$Y}C z^&oPkqgD5vvH9}R)k>S+Bp=4UP1SC9t_sQx4sv}a zl7Ae4(WNqO89VD*Z%5K^#dWAT0^uiN&yXY;w~JR=hNm7jVd0U% zOm1KLhP&sx&YbK`KrP*NUch&6|9HY=TlTf=B1uci@Vsf?EkKy~U~iM+*S|q& zhGqZNaZ~4(H_sOxfyQ^kI)OGxaMuw8cvhkc-vtM0E>8gRLu8cku;4Emz*gc%w(ra& z7(Udmn=cG2;+BrO5}qtLaP!!;Y4O^f#kh%&*=BO5Kt3J{*c?AcI4AVeK@*)o(f3rE zw_9@t&k&9&C3P7TYO+pDI?3$&oD3T%IQqn-G#78##Lq` z7B^;-h5lph!pbJkQJJ(QTH=h;d1(UxVZWcJA|& z;nkMcKZjQk9Z_YL$b)caI_YR}sh{+mSSq-^z6N7x%6?{Q=QDY<9S2WCpSQ-<;>8VB zk*7NRuEez`Re4DJy^5XY^DWJ6+fTjacv+9LC@>Dk)C{nDvYEK@TQ%x-X1=Bot zH>`+;uIZso@#B zJ(wpvSRDBBOW(HGN&4`Qt9-7?LAGbIo_Df|p$<}Wm$hoP$5p5LE>##z_c>M{_T-(S zfvh@3V^v$z8$${MPR=MMs3Kd#*lNO<+p+7^uj*$r`)9X&u7^rj=x*tRVYbR|UFdc% zjthHDgq(2fh3Yb!`lr%X!aJTCFkJGl3qpD9%r?~@ANh3-2tvcW4!fR0E)s#p?eq1l zt2bXU`JSN|=t&kCb_;I>@qSNLoIbYrqMW|`g-zjnZjaId|58O&L@Pks;`W z@srN%BL?RNxM!5zhPdt3T!fc}n(JS*J`mMzW-X65@4WYD&?WBL;p>lc-nm+q8E;7? zQhDgUsUel5OFwMLi%5$fs=PP57@cU|U;E)+)2+Kki!}WY#B^3ZjfqC)e_vW# zF4f)%A)N7xCA5uKS>;S?YLDw_ZnB zh2K%6)Fs_KG=VNqXZ5JMI~$V?i7N(8H;_OLj-MdC*k0Kdt^vhFd`9hhbU*m=BU!+3 zMd_~jiu*W^@&$<_`Vf%lOh`OYiS<4}YsX~0h; zKn0;lX-m4_sk0R0msrvq!Jn$}Rd#J_Vvf3CbT0#$m7d8ee#)-%W4@Yy-83*=r~G>L8^RAjg2UR}5xM`_A-!E3o?oQV$;TO|8=V#!Oq>Ky$AK7C~1vCceEBx_86EzV`R47URHbSEbZR!zK4sPM$Y}GpR7V?t%K7otsZ7li|}4 zjUbt=-RYUKi%1cW_lN6YGi^z2twy^@GzBdOhI!}U5B#sN2ICkcx`uT?zx>kAH~1sN zH4h=L&7!W*mUz^>q79hyYE_+spbrgIA*L(9r4t$qW0HpPsIX3H3a1kVr^Km9vaT!tW}_7lbhIXkd0<5Aq|rNa$_-c za9p)@Tk8aTf++X22}{-u!eljn%mBi!s$Gz_lQ5Zs(A`-Aug*xm(Mlj9Wg`0?Kf2rc z(0Nt=x&Ra}%;XZT6_Q*7pp(;kES|Ej)^U?i>3%9=av0@5kU*mceEu^#pE2 z>;W~wM&)t0++WjaRHC+ zGha>w#x^evJtxv8>6)gyYB|{a@#0W)h&be8AdHG#_C2t@sn7 z#o8t(FM6$SyH^z;E&AXX*;I91?%Eetjq0{%$M#~ar6YFaHAYKkRgp#6f$-d8 zKDl*B(VT*SF>b7^P1ypEo

duX;#@Z4GDQ= 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 literal 0 HcmV?d00001 From 18bbcdeb7ad91c89462bca2829d3479a9d56846a Mon Sep 17 00:00:00 2001 From: Aryamanz29 Date: Mon, 25 May 2026 22:53:23 +0530 Subject: [PATCH 2/2] fix(codex-plugin): align manifest with official spec and document sideload-only install - Fix logo rendering: prefix asset paths with ./ and add composerIcon field (Codex composer surface reads composerIcon, not logo) - Convert defaultPrompt to array and capabilities to PascalCase tokens per the canonical schema at developers.openai.com/codex/plugins/build - Align customer-facing description with Cursor plugin's copy for consistency - README: lead with sideload path since OpenAI's curated Plugin Directory is not yet GA ("coming soon" per official docs); demote curated-directory install to "once GA" footnote Co-Authored-By: Claude Opus 4.7 (1M context) --- codex-plugin/.codex-plugin/plugin.json | 21 +++++++++------------ codex-plugin/README.md | 24 +++++++++++++----------- 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/codex-plugin/.codex-plugin/plugin.json b/codex-plugin/.codex-plugin/plugin.json index 1a3936d..56102e5 100644 --- a/codex-plugin/.codex-plugin/plugin.json +++ b/codex-plugin/.codex-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "atlan", "version": "0.1.0", - "description": "Connect Codex to your Atlan data catalog. Search assets, traverse lineage, manage glossaries, define data quality rules, and govern metadata through natural language — backed by Atlan's hosted MCP server with OAuth.", + "description": "Atlan is the context layer for enterprise AI. Connect Codex to your organization's context repos — the knowledge, data, and semantics your AI agents need to build effectively. Use Atlan's agent skills to search & discover enterprise context, traverse end-to-end lineage, access governed data definitions and glossaries, execute SQL, curate your metadata graph, and ensure data quality — so every coding task in Codex is grounded in trusted organizational context.", "author": { "name": "Atlan", "email": "engineering@atlan.com", @@ -28,20 +28,17 @@ "longDescription": "Atlan is the context layer for enterprise AI. This plugin connects OpenAI Codex to your organization's Atlan tenant via Atlan's hosted MCP server, giving the agent access to your full metadata graph — tables, columns, dashboards, glossaries, domains, lineage, and data quality rules. Use it to ground coding tasks in trusted organizational context: semantic search across assets, end-to-end lineage traversal, governed data definitions, SQL execution on connected sources, and curated metadata writes. Authentication is OAuth-based against `mcp.atlan.com` — no API keys to manage.", "developerName": "Atlan", "category": "data-tools", - "capabilities": [ - "Semantic search across assets", - "Upstream and downstream lineage traversal", - "Glossary, category, and term management", - "Data domain and data product creation", - "Data quality rule authoring", - "Asset metadata updates", - "SQL execution against connected sources" - ], + "capabilities": ["Interactive", "Read", "Write"], "websiteURL": "https://atlan.com", "privacyPolicyURL": "https://atlan.com/privacy", "termsOfServiceURL": "https://atlan.com/terms", - "defaultPrompt": "Find tables related to customer data in my Atlan catalog and summarize their lineage.", + "defaultPrompt": [ + "Find tables related to customer data in my Atlan catalog and summarize their lineage.", + "List glossary terms tagged as PII in my catalog.", + "Show upstream lineage for the orders fact table." + ], "brandColor": "#0066FF", - "logo": "assets/atlan-logo.png" + "logo": "./assets/atlan-logo.png", + "composerIcon": "./assets/atlan-logo.png" } } diff --git a/codex-plugin/README.md b/codex-plugin/README.md index c0b54af..5645b8a 100644 --- a/codex-plugin/README.md +++ b/codex-plugin/README.md @@ -4,27 +4,29 @@ Connects Atlan's hosted MCP server (`https://mcp.atlan.com/mcp`) to [OpenAI Code ## Install -### From the official Codex Plugin Directory (when listed) +> **Note:** OpenAI's official Codex Plugin Directory is not yet GA. The build docs state: *"Adding plugins to the official Plugin Directory is coming soon. Self-serve plugin publishing and management are coming soon."* — see [developers.openai.com/codex/plugins/build](https://developers.openai.com/codex/plugins/build). Until then, Atlan customers install this plugin by registering Atlan's own marketplace — the steps below. -Once accepted into OpenAI's curated Plugin Directory, install via **Codex.app → Plugins → search "Atlan" → Install**, or: - -```bash -codex plugin add atlan@openai-curated -``` - -### Sideload for local development +### Sideload from this repository The repository root ships a marketplace manifest at `.agents/plugins/marketplace.json` that exposes the plugin as `atlan@atlan`. ```bash -# Register the marketplace (path = repo root containing .agents/plugins/marketplace.json) -codex plugin marketplace add /path/to/agent-toolkit +# Register Atlan's marketplace (point at the GitHub repo, or a local clone's root) +codex plugin marketplace add https://github.com/atlanhq/agent-toolkit # Install the plugin from that marketplace codex plugin add atlan@atlan ``` -Quit and relaunch **Codex.app** — the Atlan plugin appears under **Plugins → Manage** (enabled, with the bundled MCP server registered). +Quit and relaunch **Codex.app** — the Atlan plugin appears under **Plugins → Manage** (enabled, with the bundled MCP server registered). On first tool call, Codex runs OAuth against `mcp.atlan.com` to authenticate against your Atlan tenant. + +### From the official Codex Plugin Directory (once GA) + +When OpenAI opens self-serve publishing and Atlan is accepted into the curated Plugin Directory, install via **Codex.app → Plugins → search "Atlan" → Install**, or: + +```bash +codex plugin add atlan@openai-curated +``` ### Direct MCP server install (CLI only, no plugin)