MyComponent puts all extras in assets/mycomponents/componentname.
There's a trick (I think invented by splittingred) that lets you run the extra from that location in your dev. environment, but runs it from core/components when it's installed. I think it's documented in the Doodle tutorial.
Basically, you System Setting for the component's core path, assets path, and assets url (you don't always need all three). Then, all includes in your code use something like this:
include $modx->getOption('nf.core_path', null, $modx->getOption('core_path') .
'components/mycomponent/') . 'model/mycomponent/notify.class.php';
This setting is for the Notify extra and nf.core_path is set to:
{assets_path}mycomponents/notify/core/components/notify/
If the setting exists, it includes the file at:
assets/mycomponents/notify/assets/components/notify/model/notify.class.php
if the setting doesn't exist (as it wouldn't when Notify is installed by an end user), it included the file at:
core/components/notify/model/notify.class.php
getOption() works like this:
$modx->getOption('setting_to_look_for', $where to look, 'default to use if not found');
With null as the second argument, it will check the System Settings.
In system settings, {core_path} will evaluate to the MODX core path.
One gotcha with this is if you are creating a CMP. In that case you need to manually modify the core path of the namespace too and make sure that modification doesn't go into the final distribution. If you forget, your CMP is DOA for the end user.
A second gotcha is that the lexicon strings won't be read from your dev. location ($modx->lexicon->load() doesn't accept a path -- though it really should -- and always loads from the namespace path). You have to manually copy the lexicon files to core/components/componentname/lexicon.
A word of warning: Before releasing an extra, always test it in a relatively fresh install of MODX where none of the dev. System Settings are set to make sure it works.