diff --git a/docs/administrator-documentation/moderne-platform/experimental-builder.md b/docs/administrator-documentation/moderne-platform/experimental-builder.md
new file mode 100644
index 00000000..7cf6cfae
--- /dev/null
+++ b/docs/administrator-documentation/moderne-platform/experimental-builder.md
@@ -0,0 +1,5 @@
+# Experimental agent builder
+
+import CommandBuilder from '@site/src/components/CommandBuilder'
+
+
\ No newline at end of file
diff --git a/src/components/CommandBuilder.js b/src/components/CommandBuilder.js
new file mode 100644
index 00000000..365730e5
--- /dev/null
+++ b/src/components/CommandBuilder.js
@@ -0,0 +1,362 @@
+import React, { useState, useEffect } from 'react';
+import { useColorMode } from '@docusaurus/theme-common';
+
+const options = [
+ {
+ label: 'Uses GitHub',
+ value: '--github-auth',
+ id: 'github',
+ hasExtraFields: true,
+ canRepeat: true,
+ fields: [
+ {
+ label: 'Client ID',
+ key: 'clientId',
+ javaCliKey: 'moderne.agent.github[${i}].clientId',
+ dockerCliKey: 'MODERNE_AGENT_GITHUB_${i}_CLIENT_ID',
+ required: true,
+ },
+ {
+ label: 'Client Secret',
+ key: 'clientSecret',
+ javaCliKey: 'moderne.agent.github[${i}].clientSecret',
+ dockerCliKey: 'MODERNE_AGENT_GITHUB_${i}_CLIENT_SECRET',
+ required: true,
+ },
+ {
+ label: 'URL',
+ key: 'url',
+ javaCliKey: 'moderne.agent.github[${i}].url',
+ dockerCliKey: 'MODERNE_AGENT_GITHUB_${i}_URL',
+ required: false,
+ },
+ ]
+ },
+ {
+ label: 'Uses Bitbucket',
+ value: '--bitbucket-auth',
+ id: 'bitbucket',
+ hasExtraFields: true,
+ canRepeat: true,
+ fields: [
+ {
+ label: 'Client ID',
+ key: 'clientId',
+ javaCliKey: 'moderne.agent.bitbucket[${i}].clientId',
+ dockerCliKey: 'MODERNE_AGENT_BITBUCKET_${i}_CLIENT_ID',
+ required: true,
+ },
+ {
+ label: 'Client Secret',
+ key: 'clientSecret',
+ javaCliKey: 'moderne.agent.bitbucket[${i}].clientSecret',
+ dockerCliKey: 'MODERNE_AGENT_BITBUCKET_${i}_CLIENT_SECRET',
+ required: true,
+ },
+ {
+ label: 'URL',
+ key: 'url',
+ javaCliKey: 'moderne.agent.bitbucket[${i}].url',
+ dockerCliKey: 'MODERNE_AGENT_BITBUCKET_${i}_URL',
+ required: false,
+ },
+ ]
+ },
+];
+
+export default function CommandBuilder() {
+ const [cliType, setCliType] = useState('docker'); // or 'java'
+ const [selectedOptions, setSelectedOptions] = useState([]);
+ const [providerData, setProviderData] = useState({});
+ const [warningMessage, setWarningMessage] = useState('');
+ const [copied, setCopied] = useState(false);
+ const [command, setCommand] = useState('');
+ const { colorMode } = useColorMode();
+ const isDark = colorMode === 'dark';
+
+ const handleCheckboxChange = (opt) => {
+ const isSelected = selectedOptions.includes(opt.value);
+ const updated = isSelected
+ ? selectedOptions.filter((val) => val !== opt.value)
+ : [...selectedOptions, opt.value];
+
+ setSelectedOptions(updated);
+
+ if (!isSelected && opt.hasExtraFields && opt.canRepeat) {
+ setProviderData((prev) => ({
+ ...prev,
+ [opt.id]: { count: 1, inputs: {} },
+ }));
+ } else if (isSelected && opt.hasExtraFields) {
+ setProviderData((prev) => {
+ const next = { ...prev };
+ delete next[opt.id];
+ return next;
+ });
+ }
+ };
+
+ const handleFieldChange = (providerId, fieldKey, index, value) => {
+ setProviderData((prev) => ({
+ ...prev,
+ [providerId]: {
+ ...prev[providerId],
+ inputs: {
+ ...prev[providerId]?.inputs,
+ [`${fieldKey}_${index}`]: value,
+ },
+ },
+ }));
+ };
+
+ const setProviderCount = (providerId, count) => {
+ setProviderData((prev) => ({
+ ...prev,
+ [providerId]: {
+ ...prev[providerId],
+ count,
+ },
+ }));
+ };
+
+ const handleEnvToggle = (providerId, fieldKey, index, checked) => {
+ setProviderData((prev) => ({
+ ...prev,
+ [providerId]: {
+ ...prev[providerId],
+ inputs: {
+ ...prev[providerId]?.inputs,
+ [`${fieldKey}_${index}_useEnv`]: checked,
+ },
+ },
+ }));
+ };
+
+ // This function is used to generate the CLI command.
+ const buildCommand = () => {
+ let baseCmd =
+ cliType === 'java'
+ ? `mycli ${selectedOptions.filter((opt) => !opt.includes('--auth')).join(' ')}`
+ : `docker run myimage`;
+
+ let exports = [];
+ let missingFields = false;
+
+ options.forEach((opt) => {
+ if (
+ selectedOptions.includes(opt.value) &&
+ opt.hasExtraFields &&
+ opt.canRepeat
+ ) {
+ const data = providerData[opt.id];
+ if (!data) return;
+
+ for (let i = 0; i < data.count; i++) {
+ opt.fields.forEach((field) => {
+ const val = data.inputs[`${field.key}_${i}`];
+ const useEnv = data.inputs[`${field.key}_${i}_useEnv`] || false;
+
+ if (field.required && !val) {
+ missingFields = true;
+ }
+
+ if (val) {
+ const keyTemplate =
+ cliType === 'java' ? field.javaCliKey : field.dockerCliKey;
+ const resolvedKey = keyTemplate.replace('${i}', i);
+
+ if (useEnv) {
+ exports.push(`export ${resolvedKey}=${val}`);
+ baseCmd +=
+ cliType === 'java'
+ ? ` --${resolvedKey}`
+ : ` -e ${resolvedKey}`;
+ } else {
+ baseCmd +=
+ cliType === 'java'
+ ? ` --${resolvedKey}=${val}`
+ : ` -e ${resolvedKey}=${val}`;
+ }
+ }
+ });
+ }
+ }
+ });
+
+ const exportBlock = exports.length ? exports.map(line => line + '\n').join('') + '\n' : '';
+ const message = missingFields
+ ? '⚠️ Some required fields are missing.'
+ : '';
+ setWarningMessage(message);
+
+ return exportBlock + baseCmd;
+ };
+
+
+ // Update the command every time the options or data change
+ useEffect(() => {
+ const generatedCommand = buildCommand();
+ setCommand(generatedCommand); // Update the command in the state
+ }, [selectedOptions, providerData, cliType]);
+
+ const copyToClipboard = () => {
+ if (command) {
+ navigator.clipboard.writeText(command).then(() => {
+ setCopied(true);
+ setTimeout(() => setCopied(false), 2000);
+ });
+ }
+ };
+
+ return (
+
+
Build Your CLI Command
+
+
+
+
+
+
+ {options.map((opt) => (
+
+
+
+ {selectedOptions.includes(opt.value) && opt.hasExtraFields && opt.canRepeat && (
+
+
+ {[...Array(providerData[opt.id]?.count || 1)].map((_, index) => (
+
+ ))}
+
+ )}
+
+ ))}
+
+
+ {warningMessage && (
+
+ {warningMessage}
+
+ )}
+
+
+
+ {command}
+
+
+
+ {copied && (
+
+ ✅ Copied!
+
+ )}
+
+
+
+ );
+}