I am getting this all the time when I try to create macros. KM refuses to import things even though the structure is correct.
The CLI I am using to create the macros is here: rust/cli/km at main · nikivdev/rust · GitHub
I am getting this all the time when I try to create macros. KM refuses to import things even though the structure is correct.
The CLI I am using to create the macros is here: rust/cli/km at main · nikivdev/rust · GitHub
Is there something I can run to enable this automation?
What AI is trying to do:
> can you give example in text of what exactly you are trying to do
I will share it with Keyboard Maestro developer to ask what is going wrong
⏺ Here's what I'm trying to do:
Goal: Programmatically create a Keyboard Maestro macro identical to your "zed: zed"
macro, but with a different path.
Approach:
1. Generate a .kmmacros file (plist XML format)
2. Open it with open /tmp/file.kmmacros to trigger KM import
The generated file looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<array>
<dict>
<key>Activate</key>
<string>Normal</string>
<key>Name</key>
<string>zed: LMCache</string>
<key>Triggers</key>
<array/>
<key>UID</key>
<string>2BE3EA71-D7DC-4EE5-9EB8-C8B7875E6CB2</string>
<key>Actions</key>
<array>
<dict>
<key>MacroActionType</key>
<string>IfThenElse</string>
<key>TimeOutAbortsMacro</key>
<true/>
<key>Conditions</key>
<dict>
<key>ConditionList</key>
<array>
<dict>
<key>ConditionType</key>
<string>AnyWindow</string>
<key>AnyWindowConditionType</key>
<string>EndsWith</string>
<key>AnyWindowTitle</key>
<string>LMCache</string>
<key>IsFrontApplication</key>
<false/>
<key>Application</key>
<dict>
<key>BundleIdentifier</key>
<string>dev.zed.Zed</string>
<key>Name</key>
<string>Zed</string>
<key>NewFile</key>
<string>/Applications/Zed.app</string>
</dict>
</dict>
</array>
<key>ConditionListMatch</key>
<string>All</string>
</dict>
<key>ThenActions</key>
<array>
<dict>
<key>MacroActionType</key>
<string>ManipulateWindow</string>
<key>Action</key>
<string>SelectWindow</string>
<key>Targeting</key>
<string>WindowNameContaining</string>
<key>TargetingType</key>
<string>Specific</string>
<key>WindowName</key>
<string>LMCache</string>
<key>TargetApplication</key>
<dict>
<key>BundleIdentifier</key>
<string>dev.zed.Zed</string>
<key>Name</key>
<string>Zed</string>
<key>NewFile</key>
<string>/Applications/Zed.app</string>
</dict>
</dict>
</array>
<key>ElseActions</key>
<array>
<dict>
<key>MacroActionType</key>
<string>ExecuteShellScript</string>
<key>DisplayKind</key>
<string>Window</string>
<key>HonourFailureSettings</key>
<true/>
<key>IncludeStdErr</key>
<false/>
<key>Path</key>
<string></string>
<key>Source</key>
<string>Nothing</string>
<key>Text</key>
<string>open -a /Applications/Zed.app ~/fork-i/LMCache/LMCache</string>
<key>TimeOutAbortsMacro</key>
<true/>
<key>TrimResults</key>
<true/>
<key>TrimResultsNew</key>
<true/>
<key>UseText</key>
<true/>
</dict>
</array>
</dict>
</array>
</dict>
</array>
</plist>
Error: When opening this file, Keyboard Maestro shows "Cannot Import Macro File - The
Macro File you selected is of an unknown format."
The file passes plutil -lint validation. The structure is modeled after what get xml
of macro "zed: zed" returns, wrapped in an <array> since .kmmacros files need to be
arrays of macros.
⏺ Here's the summary for the KM developer:
---
Goal: Programmatically create Keyboard Maestro macros via CLI by generating .kmmacros
files and opening them.
Command I run:
km create-open "zed: LMCache" Zed "~/fork-i/LMCache/LMCache"
What my CLI does:
1. Generates a .kmmacros plist file at /tmp/km_macro_import.kmmacros
2. Runs open /tmp/km_macro_import.kmmacros
The generated file:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<array>
<dict>
<key>Activate</key>
<string>Normal</string>
<key>Name</key>
<string>zed: LMCache</string>
<key>Triggers</key>
<array/>
<key>UID</key>
<string>2BE3EA71-D7DC-4EE5-9EB8-C8B7875E6CB2</string>
<key>Actions</key>
<array>
<dict>
<key>MacroActionType</key>
<string>IfThenElse</string>
<key>TimeOutAbortsMacro</key>
<true/>
<key>Conditions</key>
<dict>
<key>ConditionList</key>
<array>
<dict>
<key>ConditionType</key>
<string>AnyWindow</string>
<key>AnyWindowConditionType</key>
<string>EndsWith</string>
<key>AnyWindowTitle</key>
<string>LMCache</string>
<key>IsFrontApplication</key>
<false/>
<key>Application</key>
<dict>
<key>BundleIdentifier</key>
<string>dev.zed.Zed</string>
<key>Name</key>
<string>Zed</string>
<key>NewFile</key>
<string>/Applications/Zed.app</string>
</dict>
</dict>
</array>
<key>ConditionListMatch</key>
<string>All</string>
</dict>
<key>ThenActions</key>
<array>
<dict>
<key>MacroActionType</key>
<string>ManipulateWindow</string>
<key>Action</key>
<string>SelectWindow</string>
<key>Targeting</key>
<string>WindowNameContaining</string>
<key>TargetingType</key>
<string>Specific</string>
<key>WindowName</key>
<string>LMCache</string>
<key>TargetApplication</key>
<dict>
<key>BundleIdentifier</key>
<string>dev.zed.Zed</string>
<key>Name</key>
<string>Zed</string>
<key>NewFile</key>
<string>/Applications/Zed.app</string>
</dict>
</dict>
</array>
<key>ElseActions</key>
<array>
<dict>
<key>MacroActionType</key>
<string>ExecuteShellScript</string>
<key>DisplayKind</key>
<string>Window</string>
<key>HonourFailureSettings</key>
<true/>
<key>IncludeStdErr</key>
<false/>
<key>Path</key>
<string></string>
<key>Source</key>
<string>Nothing</string>
<key>Text</key>
<string>open -a /Applications/Zed.app ~/fork-i/LMCache/LMCache</string>
<key>TimeOutAbortsMacro</key>
<true/>
<key>TrimResults</key>
<true/>
<key>TrimResultsNew</key>
<true/>
<key>UseText</key>
<true/>
</dict>
</array>
</dict>
</array>
</dict>
</array>
</plist>
Error: "Cannot Import Macro File - The Macro File you selected is of an unknown
format."
Validation: plutil -lint /tmp/km_macro_import.kmmacros returns OK.
Question: What is the correct plist format for a .kmmacros file? Is there a way to
programmatically create macros via AppleScript or another API?
The KM message is saying that the xml is a valid plist, but not valid KM export structure.
Your plist is an array of Macros.
It needs to be embedded in a macro group under a Macros key. That macro group needs to. be wrapped in an array.
That will tell KM the macro's destination.
In my testing, this is the minimal macro export structure.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<array>
<dict>
<key>Macros</key>
<array>
<dict>
<key>Actions</key>
<array/>
<key>Name</key>
<string>Minimal Macro</string>
<key>Triggers</key>
<array/>
</dict>
</array>
<key>Name</key>
<string>Test Group</string>
</dict>
</array>
</plist>
(0-based numbering)
plist (version="1.0")
└─ array (root array)
└─ [0] dict "Macro Group"
├─ key "Macros" → array
│ └─ [0] dict "Macro"
│ ├─ key "Actions" → array (empty)
│ ├─ key "Name" → string "Minimal Macro"
│ └─ key "Triggers" → array (empty)
└─ key "Name" → string "Test Group"
Import it like this:
--How to create/import macros into Keyboard Maestro from code? - Questions & Suggestions - Keyboard Maestro Discourse
-- https://forum.keyboardmaestro.com/t/how-to-create-import-macros-into-keyboard-maestro-from-code/50798/2
use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions
set minimalExportXML to ¬
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
<plist version=\"1.0\">
<array>
<dict>
<key>Macros</key>
<array>
<dict>
<key>Actions</key>
<array/>
<key>Name</key>
<string>Minimal Macro</string>
<key>Triggers</key>
<array/>
</dict>
</array>
<key>Name</key>
<string>Test Group</string>
</dict>
</array>
</plist>"
tell application id "com.stairways.keyboardmaestro.editor"
importMacros minimalExportXML
end tell
Another the example is here:
This AppleScript will properly wrap and import your xml.
--How to create/import macros into Keyboard Maestro from code? - Questions & Suggestions - Keyboard Maestro Discourse
-- https://forum.keyboardmaestro.com/t/how-to-create-import-macros-into-keyboard-maestro-from-code/50798/2
use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use scripting additions
set arrayOfMacroDicts to "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\"
\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
<plist version=\"1.0\">
<array>
<dict>
<key>Activate</key>
<string>Normal</string>
<key>Name</key>
<string>zed: LMCache</string>
<key>Triggers</key>
<array/>
<key>UID</key>
<string>2BE3EA71-D7DC-4EE5-9EB8-C8B7875E6CB2</string>
<key>Actions</key>
<array>
<dict>
<key>MacroActionType</key>
<string>IfThenElse</string>
<key>TimeOutAbortsMacro</key>
<true/>
<key>Conditions</key>
<dict>
<key>ConditionList</key>
<array>
<dict>
<key>ConditionType</key>
<string>AnyWindow</string>
<key>AnyWindowConditionType</key>
<string>EndsWith</string>
<key>AnyWindowTitle</key>
<string>LMCache</string>
<key>IsFrontApplication</key>
<false/>
<key>Application</key>
<dict>
<key>BundleIdentifier</key>
<string>dev.zed.Zed</string>
<key>Name</key>
<string>Zed</string>
<key>NewFile</key>
<string>/Applications/Zed.app</string>
</dict>
</dict>
</array>
<key>ConditionListMatch</key>
<string>All</string>
</dict>
<key>ThenActions</key>
<array>
<dict>
<key>MacroActionType</key>
<string>ManipulateWindow</string>
<key>Action</key>
<string>SelectWindow</string>
<key>Targeting</key>
<string>WindowNameContaining</string>
<key>TargetingType</key>
<string>Specific</string>
<key>WindowName</key>
<string>LMCache</string>
<key>TargetApplication</key>
<dict>
<key>BundleIdentifier</key>
<string>dev.zed.Zed</string>
<key>Name</key>
<string>Zed</string>
<key>NewFile</key>
<string>/Applications/Zed.app</string>
</dict>
</dict>
</array>
<key>ElseActions</key>
<array>
<dict>
<key>MacroActionType</key>
<string>ExecuteShellScript</string>
<key>DisplayKind</key>
<string>Window</string>
<key>HonourFailureSettings</key>
<true/>
<key>IncludeStdErr</key>
<false/>
<key>Path</key>
<string></string>
<key>Source</key>
<string>Nothing</string>
<key>Text</key>
<string>open -a /Applications/Zed.app ~/fork-i/LMCache/LMCache</string>
<key>TimeOutAbortsMacro</key>
<true/>
<key>TrimResults</key>
<true/>
<key>TrimResultsNew</key>
<true/>
<key>UseText</key>
<true/>
</dict>
</array>
</dict>
</array>
</dict>
</array>
</plist>"
--Deserialize the array of macros
set macroDicts to (current application's NSString's stringWithString:arrayOfMacroDicts)'s propertyList()
--embed the array of macros into the Macros key of a Macro Group dict
set groupDict to {Macros:macroDicts, |Name|:"tests"}
--wrap the Macro Group dict in an Array
set groupsArray to {groupDict}
--convert back to xml
set exportXML to serializePlistObject(groupsArray)
tell application id "com.stairways.keyboardmaestro.editor"
importMacros exportXML
end tell
on serializePlistObject(plistObject)
set {theData, theError} to current application's NSPropertyListSerialization's dataWithPropertyList:plistObject format:(current application's NSPropertyListXMLFormat_v1_0) options:0 |error|:(reference) -- don't use binary format
if theData is missing value then error (theError's localizedDescription() as text) number -10000
set plist to (current application's NSString's alloc()'s initWithData:theData encoding:(current application's NSUTF8StringEncoding)) as text
end serializePlistObject
(If memory serves, when KM exports macros, it wraps each macro in a macro group individually, but in practice you can put an array of Macros that share the same destination into one Macro Group.
This worked wonderfully, thank you. Updated the CLI in case anyone wants to use it.